1、通过上一节【】,我们对消息队列和jms 有了一定的了解,但是像第一节中编写异步消息通讯比较麻烦,通过与spring的整合,我们使用起来会非常简单。
本例子采用maven构建,具体代码如下所示:
pom文件如下:主要使用的jar包有spring相关的,junit相关,mq相关
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<!-- activemq -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-spring</artifactId>
<version>${activemq.version}</version>
</dependency>
<!-- spring-jms -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
activemq 相关配置文件如下:
applicationContext-activemq.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd"
default-lazy-init="false">
<!-- ActiveMQ 连接工厂 -->
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
<!-- 如果连接网络:tcp://ip:61616;未连接网络:tcp://localhost:61616 以及用户名,密码-->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="${activemq.url}"
trustAllPackages="true" userName="${activemq.username}" password="${activemq.password}" />
<!-- Spring Caching连接工厂 -->
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<!-- Session缓存数量 -->
<property name="sessionCacheSize" value="${activemq.sessioncachesize}"></property>
</bean>
<!-- Spring JmsTemplate 的消息生产者 start-->
<!-- 定义JmsTemplate的Queue类型 -->
<bean id="queueTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<constructor-arg ref="connectionFactory" />
<!-- 非pub/sub模型(发布/订阅),即队列模式 -->
<property name="pubSubDomain" value="false" />
</bean>
<!--Spring JmsTemplate 的消息生产者 end-->
</beans>
生产者如下:
/**
* mq 生产者
* @author Administrator
*
*/
@Service
public class StudentProducerService {
public final static Logger logger = LoggerFactory.getLogger(StudentProducerService.class);
/**
* 队列名称
*/
@Value("${test.queue}")
private String queueName;
@Autowired
private JmsTemplate queueTemplate;
/**
* 将消息发送至mq的队列中
*/
public void sendMessage(final Student student){
queueTemplate.send(queueName, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
ObjectMessage message = session.createObjectMessage();
logger.debug("生产者将发送消息:【producer】"+student.toString());
message.setObject(student);
return message;
}
});
}
}
消费者:
/**
* mq 消费者
* @author Administrator
*
*/
@Service
public class StudentConsumerService {
public final static Logger logger = LoggerFactory.getLogger(StudentConsumerService.class);
/**
* 队列名称
*/
@Value("${test.queue}")
private String queueName;
@Autowired
private JmsTemplate queueTemplate;
/**
* 接收消息
*/
public void receiverMessage(){
Message message = (Message) queueTemplate.receive(queueName);
ObjectMessage objMessage = (ObjectMessage) message;
try {
Object obj = objMessage.getObject();
if(obj instanceof Student){
logger.debug("服务器收到消息:+【receiver】"+obj.toString());
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
测试运行代码如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring/applicationContext*.xml"})
public class StudentProducerServiceTest {
@Autowired
private StudentProducerService studentProducerService;
@Autowired
private StudentConsumerService studentConsumerService;
@Test
public void testSendMessage() {
final Student student = new Student("201712291122", "onionflower", 12, 2);
System.out.println("准备开始运行生产者。。。。");
studentProducerService.sendMessage(student);
System.out.println("准备开始运行消费者。。。。");
studentConsumerService.receiverMessage();
}
}
运行结果:
从上面的测试结果我们可以看到,生产者生产一条消息,消费者消费一条消息,但我们会发现该用例存在问题:
1、消费者需要手动运行,做不到随时监听队列【如果发现有消息,自动进行消费】。
2、代码不够优化。
优化后代码如下:
配置文件增加:
applicationContext-activemq.xml
<bean id="queueReceiver" class="com.onion.mq.optimize.OptimizeConsumerService"></bean>
<!-- 定义Queue监听器 -->
<jms:listener-container destination-type="queue" container-type="default" receive-timeout="5000" connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="${test.queue}" ref="queueReceiver"/>
</jms:listener-container>
生产者:
/**
* 优化之后的生产者
* @author Administrator
*
*/
@Service
public class OptimizeProducerService{
public final static Logger logger = LoggerFactory.getLogger(OptimizeProducerService.class);
/**
* 队列名称
*/
@Value("${test.queue}")
private String queueName;
/**
* 对jmstemplete 的包装,将发送消息的方法统一包装
*/
@Autowired
private MqService mqService;
/**
* 将消息发送至mq的队列中
*/
public void sendMessage( Student student){
logger.debug("生产者将发送消息:【producer】"+student.toString());
StudentMessageCreator studentCreator = new StudentMessageCreator(student);
mqService.queueSend(queueName, studentCreator);
}
}
封装jmsTemplete
/**
* @author onionflower
* @date 2017年7月12日
*/
@Service
public class MqService {
@Autowired(required=false)
private JmsTemplate queueTemplate;
public void queueSend(String queueName,MessageCreator messageCreator){
queueTemplate.send(queueName,messageCreator);
}
}
将messageCreator提取出来
/**
* 优化产生的代码,我们将生产者中的new MessageCreator提取出来,单独生成一个类
* @author Administrator
*
*/
public class StudentMessageCreator implements MessageCreator{
private Student student;
public StudentMessageCreator(Student student) {
super();
this.student = student;
}
@Override
public Message createMessage(Session session) throws JMSException {
ObjectMessage message = session.createObjectMessage();
message.setObject(student);
return message;
}
}
消费者:
/**
* mq 消费者
* @author Administrator
*
*/
public class OptimizeConsumerService implements MessageListener{
public final static Logger logger = LoggerFactory.getLogger(OptimizeConsumerService.class);
@Override
public void onMessage(Message message) {
ObjectMessage objMessage = (ObjectMessage) message;
Object obj = null;
try {
obj = objMessage.getObject();
if(obj instanceof Student){
logger.debug("服务器收到消息:+【receiver】"+obj.toString());
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
运行结果如下:
我们只需要运行生产者,消费者会自动监听队列中是否有未消费的消息,如果有,直接拿过去消费。
二、ActiveMQ集群配置
activemq集群,我们只需要修改spring的配置文件:将连接工厂的相关配置修改即可。具体代码如下:
<amq:connectionFactory id="amqConnectionFactory" brokerURL="${activemq.url}"
trustAllPackages="true" userName="${activemq.username}" password="${activemq.password}" />
关于properties配置文件如下:
activemq.url=failover:(tcp://xxxx:61616,tcp://xxxxx:61616,tcp://xxxxx:61616)?initialReconnectDelay=0&maxReconnectAttempts=3&timeout=2000
activemq.username=admin
activemq.password=admin
activemq.sessioncachesize=100
源码下载地址如下:http://download.csdn.net/download/u012151597/10179978