点对点消息传送模型允许JMS客户端通过队列这个虚拟通道来同步和异步发送、接收消息。
在点对点消息传送模型中,消息生产者称为发送者,消息消费者称为接收者
消费者是基于拉取(pull)或基于轮询(polling)来从队列中请求消息,队列并不会自动地将消息推送到客户端
一个消息有且只能被一个消费者接收,即使有多个消费者同时监听了队列
点对点模型支持负载均衡,允许多个消费者监听同一个队列,并以此来分配负载
Spring Framework 为JMS提供了内置支持,Spring提供了JMS模板和消息监听容器
JMS实现采用ActiveMQ
定义消息生产者
public interface ProducerService {
/**
* P2P 点对点模式生产者发送消息.
*
* @param destination
* @param message
*/
public void sendMessage(Destination destination, String message);
}
@Component("producerService")
public class ProducerServiceImpl implements ProducerService {
//Spring JMS Template
@Resource(name="jmsTemplate")
private JmsTemplate jmsTemplate;
/**
* P2P 点对点模式生产者发送消息.
*
* @param destination
* @param message
*/
@Override
public void sendMessage(Destination destination, final String message) {
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(message);
}
});
}
}
设置一个定时任务充当消息生产者,每隔两秒发送一条消息,消息内容为当前时间
@Component(value = "poll")
public class Poll {
// ActiveMQ生产者
@Resource(name = "producerService")
private ProducerService producerService;
// ActiveMQ 预先预约运单号队列目的地
@Resource(name = "queueDestination")
private Destination destination;
@Scheduled(cron="0/2 * * * * ?")
public void getTradeIncrement() {
producerService.sendMessage(destination, "当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
定义一个消费者监听队列:
public class ConsumerMessageListener implements MessageListener{
@Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
String num = textMessage.getText();
System.out.println(num);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
JMS配置文件:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="maxConnections" value="10" />
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="pooledConnectionFactory" />
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<property name="connectionFactory" ref="connectionFactory" />
</bean>
<!--这个是队列目的地 -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>queue</value>
</constructor-arg>
</bean>
<!-- 消息监听器 -->
<bean id="consumerMessageListener" class="com.dragon.jms.listener.ConsumerMessageListener" />
<!-- 消息监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" />
<property name="messageListener" ref="consumerMessageListener" />
</bean>
</beans>
如果多个消费者同时监听队列,那么消息将在均衡分布于每个消费者进行消费,是消息可靠性的一种方式,称为队列消费者集群(Queue consumer clusters)
public class ConsumerAMessageListener implements MessageListener{
@Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
String num = textMessage.getText();
System.out.println("A " + num);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
public class ConsumerBMessageListener implements MessageListener{
@Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
String num = textMessage.getText();
System.out.println("B " + num);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
public class ConsumerCMessageListener implements MessageListener{
@Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
String num = textMessage.getText();
System.out.println("C " + num);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
此时需为每一个消息监听器添加一个消息监听容器:
<!-- 消息监听器 -->
<bean id="consumerAMessageListener" class="com.dragon.jms.listener.ConsumerAMessageListener" />
<bean id="consumerBMessageListener" class="com.dragon.jms.listener.ConsumerBMessageListener" />
<bean id="consumerCMessageListener" class="com.dragon.jms.listener.ConsumerCMessageListener" />
<!-- 消息监听容器 -->
<bean id="jmsAContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" />
<property name="messageListener" ref="consumerAMessageListener" />
</bean>
<bean id="jmsBContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" />
<property name="messageListener" ref="consumerBMessageListener" />
</bean>
<bean id="jmsCContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" />
<property name="messageListener" ref="consumerCMessageListener" />
</bean>
结果:
C 当前时间:2016-03-04 13:29:08
A 当前时间:2016-03-04 13:29:10
B 当前时间:2016-03-04 13:29:12
C 当前时间:2016-03-04 13:29:14
A 当前时间:2016-03-04 13:29:16
B 当前时间:2016-03-04 13:29:18
C 当前时间:2016-03-04 13:29:20
A 当前时间:2016-03-04 13:29:22
B 当前时间:2016-03-04 13:29:24
C 当前时间:2016-03-04 13:29:26
A 当前时间:2016-03-04 13:29:28
B 当前时间:2016-03-04 13:29:30
C 当前时间:2016-03-04 13:29:32
A 当前时间:2016-03-04 13:29:34
B 当前时间:2016-03-04 13:29:36
C 当前时间:2016-03-04 13:29:38
A 当前时间:2016-03-04 13:29:40
B 当前时间:2016-03-04 13:29:42
消息均衡的由三个消费者消费,提高系统的负载和可靠性,当某个消费者无法正常工作时,也不影响队列中消息的消费