jms activeMQ与spring集成进阶篇
来源:互联网 发布:京东内部下单软件 编辑:程序博客网 时间:2024/05/01 04:32
前不久,刚学习了jms的简单入门,后面紧接着就做了一个关于jms的负载均衡的项目,做完之后颇有打通任督二脉的感觉,感觉很多之前不是很理解的东西,都有些理解了,比如服务器端的监听、具体的jms的使用等,收获有点大。
流程如下图所示:
客户端:
xml配置,这里用到了两台服务器,connectionFactory便可以看出,因为传的是对象,用到了转换器
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <beans xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-2.5.xsd">10 11 12 <!-- 配置JMS连接工厂 -->13 14 <!-- <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">-->15 <!-- <property name="brokerURL" value="tcp://localhost:61616" />-->16 <!-- </bean>-->17 18 <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">19 <property name="connectionFactory">20 <bean class="org.apache.activemq.ActiveMQConnectionFactory">21 <property name="brokerURL">22 <value>tcp://localhost:61616</value>23 </property>24 <property name="useAsyncSend">25 <value>true</value>26 </property>27 </bean>28 </property>29 </bean>30 31 32 <bean id="connectionFactory_1" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">33 <property name="connectionFactory">34 <bean class="org.apache.activemq.ActiveMQConnectionFactory">35 <property name="brokerURL">36 <value>tcp://192.168.130.13:61616</value>37 </property>38 <property name="useAsyncSend">39 <value>true</value>40 </property>41 </bean>42 </property>43 </bean>44 45 <!-- 发送消息的目的地(一个队列) -->46 <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">47 <!-- 设置消息队列的名字 -->48 <constructor-arg index="0" value="activeMQQueue" />49 </bean>50 51 52 <!-- 消息转换 -->53 <bean id="messageConverter" class="com.pis.activeMQ.ObjectMessageConverter"/>54 55 56 <!-- 配置JMS模版 -->57 <bean id="jmsTemplate_1" class="org.springframework.jms.core.JmsTemplate">58 <property name="connectionFactory" ref="connectionFactory" />59 <property name="messageConverter" ref="messageConverter" />60 </bean>61 62 <bean id="jmsTemplate_2" class="org.springframework.jms.core.JmsTemplate">63 <property name="connectionFactory" ref="connectionFactory_1" />64 <property name="messageConverter" ref="messageConverter" />65 </bean>66 67 68 <!-- 生产消息配置 -->69 <bean id="queueProducer" class="com.pis.activeMQ.client.MessageProducer">70 <property name="destination" ref="destination"/>71 <property name="jmsTemplate"> 72 <list> 73 <ref bean="jmsTemplate_1" /> 74 <ref bean="jmsTemplate_2" /> 75 </list> 76 </property>77 </bean>78 79 80 <!-- 生产消息action bean -->81 <bean id="jmsAction" class="com.pis.action.JmsAction">82 <property name="queueProducer" ref="queueProducer"/>83 </bean>84 85 </beans>
转换器如下所示: 转来转去有点恶心的代码 O(∩_∩)O~
1 package com.pis.activeMQ; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.io.ObjectInputStream; 7 import java.io.ObjectOutputStream; 8 9 import javax.jms.JMSException;10 import javax.jms.Message;11 import javax.jms.ObjectMessage;12 import javax.jms.Session;13 14 import org.springframework.jms.support.converter.MessageConversionException;15 import org.springframework.jms.support.converter.MessageConverter;16 17 public class ObjectMessageConverter implements MessageConverter{18 19 20 21 //从消息中取出对象22 @Override23 public Object fromMessage(Message message) throws JMSException,MessageConversionException {24 Object object = null;25 if(message instanceof ObjectMessage) {26 27 //两次强转,获得消息中的主体对象字节数组流28 byte[] obj = (byte[])((ObjectMessage)message).getObject();29 //读取字节数组中为字节数组流30 ByteArrayInputStream bis = new ByteArrayInputStream(obj);31 try {32 // 读字节数组流为对象输出流33 ObjectInputStream ois = new ObjectInputStream(bis);34 // 从对象输出流中取出对象 并强转35 object = ois.readObject();36 } catch (Exception e) {37 e.printStackTrace();38 }39 }40 return object;41 }42 43 44 //将对象转换成消息45 @Override46 public Message toMessage(Object object, Session session) throws JMSException,MessageConversionException {47 ObjectMessage objectMessage = session.createObjectMessage();48 49 ByteArrayOutputStream bos = new ByteArrayOutputStream();//字节数组输出流50 try {51 ObjectOutputStream oos = new ObjectOutputStream(bos);//对象输出流52 53 oos.writeObject(object);//写入对象54 55 byte[] objMessage = bos.toByteArray();//字节数组输出流转成字节数组56 57 objectMessage.setObject(objMessage);//将字节数组填充到消息中作为消息主体 58 59 } catch (IOException e) {60 e.printStackTrace();61 }62 63 return objectMessage;64 }65 66 67 }
生产者 这里用到了原子类来计数,避免使用线程同步,也是第一次接触,convertAndSend方法会调用转换器,把对象转换成消息类型
1 package com.pis.activeMQ.client; 2 3 import java.util.List; 4 import java.util.concurrent.atomic.AtomicInteger; 5 6 import org.apache.activemq.command.ActiveMQQueue; 7 import org.springframework.jms.core.JmsTemplate; 8 9 import com.pis.model.Product;10 11 public class MessageProducer {12 private ActiveMQQueue destination;13 14 private List<JmsTemplate> jmsTemplate;15 16 private Product product;17 18 //原子整型计数(CAS),可以不使用同步19 private AtomicInteger current = new AtomicInteger(0);20 21 //轮询算法解决负载均衡22 private JmsTemplate findJmsTemplate(){23 int cur = current.getAndIncrement();24 int index = cur%jmsTemplate.size();25 return jmsTemplate.get(index);26 }27 28 //发送消息29 public void sendMessage(Product product){30 this.findJmsTemplate().convertAndSend(destination, product);31 }32 33 public ActiveMQQueue getDestination() {34 return destination;35 }36 37 public void setDestination(ActiveMQQueue destination) {38 this.destination = destination;39 }40 41 public List<JmsTemplate> getJmsTemplate() {42 return jmsTemplate;43 }44 45 public void setJmsTemplate(List<JmsTemplate> jmsTemplate) {46 this.jmsTemplate = jmsTemplate;47 }48 49 public Product getProduct() {50 return product;51 }52 53 public void setProduct(Product product) {54 this.product = product;55 }56 57 58 59 60 }
服务器端:
xml配置如下:这里只是我本机的服务器配置,另外一台如法炮制,这里用到了监听器,见名知意,大概干嘛用的一看就知道,有消息是会触发监听器,监听器指定使用queueConsumer中的receive方法,这就很清楚了,来一条收一条,来两条收一双。
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <beans xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-2.5.xsd">10 11 12 13 <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">14 <property name="connectionFactory">15 <bean class="org.apache.activemq.ActiveMQConnectionFactory">16 <property name="brokerURL">17 <value>tcp://localhost:61616</value>18 </property>19 <property name="useAsyncSend">20 <value>true</value>21 </property>22 </bean>23 </property>24 </bean>25 26 27 <!-- 发送消息的目的地(一个队列) -->28 <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">29 <!-- 设置消息队列的名字 -->30 <constructor-arg index="0" value="activeMQQueue" />31 </bean>32 33 34 <!-- 消息转换 -->35 <bean id="messageConverter" class="com.pis.activeMQ.ObjectMessageConverter"/>36 37 <!-- 生产消息配置 -->38 <bean id="queueConsumer" class="com.pis.activeMQ.server.MessageConsumer"/>39 40 41 <bean id="queueListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">42 <constructor-arg ref="queueConsumer"/>43 <property name="defaultListenerMethod" value="receive"/>44 <property name="messageConverter" ref="messageConverter"/>45 </bean>46 47 <bean id="queueListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">48 <property name="connectionFactory" ref="connectionFactory"/>49 <property name="destination" ref="destination" />50 <property name="messageListener" ref="queueListener" />51 </bean>52 53 </beans>
消费者 很简洁的代码
1 package com.pis.activeMQ.server; 2 3 import com.pis.model.Product; 4 5 public class MessageConsumer { 6 public void receive(Product product) { 7 8 //如果消费到了就会打印出来 9 System.out.println("server端收到消息:"+product.getName());10 }11 }
好了,我这是个struts2+spring的代码,有了第一个xml中的jmsAction的配置,下面就是action的代码
1 package com.pis.action; 2 3 import com.opensymphony.xwork2.ActionSupport; 4 import com.pis.activeMQ.client.MessageProducer; 5 import com.pis.model.Product; 6 7 8 public class JmsAction extends ActionSupport { 9 10 private static final long serialVersionUID = 132132131312L;11 12 private MessageProducer queueProducer;13 14 private Product product;15 16 17 18 @Override19 public String execute() throws Exception {20 System.out.println(product.getName());21 22 queueProducer.sendMessage(product);23 24 return null;25 }26 27 public MessageProducer getQueueProducer() {28 return queueProducer;29 }30 31 public void setQueueProducer(MessageProducer queueProducer) {32 this.queueProducer = queueProducer;33 }34 35 public Product getProduct() {36 return product;37 }38 39 public void setProduct(Product product) {40 this.product = product;41 }42 43 44 }
product类,记得要实现serializable方法!
1 package com.pis.model; 2 3 import java.io.Serializable; 4 5 6 public class Product implements Serializable{ 7 8 private String name; 9 10 public String getName() {11 return name;12 }13 public void setName(String name) {14 this.name = name;15 }16 17 }
好吧,struts中的配置我就不给了,太简单了,直接访问 localhost:8060/pis/produceMessage.action?product.name=85252 顺便说下,由于懒,这里我就直接把product实体类当成参数传进去了,吼吼,没有界面……懒吧
期间测试可以看http://localhost:8161/admin/queues.jsp 和http://192.168.130.13:8161/admin/queues.jsp可以很明显的看出每次浏览器回车一下,只有其中的一个消息多列一条,完美实现了负载均衡,并且对object类型的message队列学习了一下,收获很大
- jms activeMQ与spring集成进阶篇
- jms activeMQ与spring集成进阶篇
- jms activeMQ与spring集成进阶篇(转载)
- jms activeMQ与spring集成进阶篇(转载)
- jms activeMQ与spring的集成
- jms activeMQ与spring的集成
- jms之activeMQ与spring集成进阶-实现一种负载均衡
- JMS 集成Spring 实现ActiveMQ
- Spring JMS和ActiveMQ集成
- (七)jms activeMQ与spring的集成
- JMS之ActiveMQ(含与Spring集成使用)
- jms activeMQ与spring的集成(转载)
- JMS-ActiveMq与Spring整合
- ActiveMQ(二)-Spring集成JMS
- ActiveMQ学习笔记(二) JMS与Spring
- Spring与ActiveMQ(JMS)的整合说明
- Spring JMS与ActiveMQ通讯示列
- activemq与spring集成配置
- C语言指针5分钟教程
- 树形结构的数据库表Schema设计-基于左右值编码
- VC++编译错误信息
- android中用Spannable在TextView中设置超链接、颜色、字体
- 关于Android发送邮件
- jms activeMQ与spring集成进阶篇
- xmemcached
- 如何使用github
- 微软发布安全通报2847140
- 使用Spread Studio for .NET如何选择工作表
- Kestrel持久化队列服务器
- Suse Linux下内存使用率精细解读
- menuconfig---Unable to find the Ncurses libraries问题解决
- oracle数据库恢复方法及ORA-01991错误的解决