Spring JMS 异常消息接收
消息监听器容器
Spring 在 org.sprinframework.jms.listener 包中提供了若干个的不依赖于 JMS 提供者的消息报监听器容器 , 允许开发者注入一个消息监听器 , 管理器将周期性查看 MOM 中指定的地址的消息 , 如果消息到达时 , 管理使用 TaskExecutor 以异步的方式执行消息监听器的动作
SimpleMessageListenerContainer
最简单的消息监听容器 , 直接使用 JMS API 的 MessageConsumer.setMessageListener() 工作 ; 引入 TaskExecutor 将消息监听器改造成独立线程执行的异步执行器 ; 并创建多个 MessageConsumer 实例 , 注册这个监听器 , 以便多个 MessageConsumer 发送执行 .
DefaultMessageListenerConatainer
通过循环机制执行 MessageConsumer.receiver() 方法 , 获取目标地址的消息 , 引入 TaskExecutor 机制让同步获取消息的 receive() 方法在独立线程环境下异步执行
maxConcurrentConsumers
idleTaskExecutionLimit
ServerSessionMessageListenerContainer
基于标准 JMS 提供一个最复杂的消息监听器容器 , 需要注入一个 ServerSessionFactory, 用于创建 ServerSessionp 实例 , 对 Session 进行池缓存技术并发接收消息
相同特性 :sessionAcknowledgeMode:int 消息的确认方式
destination destinationName
messageSeclector
autoStartup Boolean
注意 : 一个消息监听容器只能管理一个消息监听器
异步接收消息
编写一个简单的消息监听器
SimpleMessageListener.java
package cn.com.snt.async_jms;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
public class SimpleMessageListener implements MessageListener {
public void onMessage(Message message) {
try {
if(message instanceof ObjectMessage){
ObjectMessage objMsg=(ObjectMessage)message;
User usr=(User)objMsg.getObject();
System.out.println("user:"+usr);
}else{
System.out.println("warning not ObjectMessage");
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
接下来 , 将这个消息监听器注册到 DefaultMessageListenerConatainer 中
applicationContext-receiver.xml
<? xml version = "1.0" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:amq = "http://activemq.org/config/1.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.org/config/1.0 http://people.apache.org/repository/org.apache.activemq/xsds/activemq-core-4.1-incubator-SNAPSHOT.xsd" >
< bean id = "connectionFactory" class = "org.apache.activemq.pool.PooledConnectionFactory" >
< property name = "connectionFactory" >
< bean class = "org.apache.activemq.ActiveMQConnectionFactory" >
< property name = "brokerURL" value = "tcp://localhost:61616" />
</ bean >
</ property >
</ bean >
// 这里生产 Pub/Sub 域消息
< bean id = "dest" class = "org.apache.activemq.command. ActiveMQTopic " >
< constructor-arg value = "userMsgQ" />
</ bean >
< bean id = "messageListener" class = "cn.com.snt.async_jms.SimpleMessageListener" />
< bean id = "listenerContainer" class = "org.springframework.jms.listener.DefaultMessageListenerContainer" >
< property name = "connectionFactory" ref = "connectionFactory" />
< property name = "destination" ref = "dest" /> // 注册消息监听器
<property name="messageListener" ref="messageListener"/>
< property name = "maxConcurrentConsumers" value = "10" />
< property name = "idleTaskExecutionLimit" value = "2" />
</ bean >
</ beans >
测试接收类 :receiver.java
package cn.com.snt.async_jms;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Receiver {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("cn/com/snt/async_jms/applicationContext-receiver.xml");
}
}
发送消息
package cn.com.snt.async_jms;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.jms.core.support.JmsGatewaySupport;
public class MessageSender extends JmsGatewaySupport {
public void sendUserMessage(User usr){
getJmsTemplate().convertAndSend(usr);
}
public void sendUserMessage1(User usr){
//getJmsTemplate().convertAndSend(destination, usr);
}
/**
* 使用 MessagePostProcessor 对
* POJO 转换为 Meesage 后进行后处理
* @param usr
*/
public void sendUserMessage2(User usr){
getJmsTemplate().convertAndSend(usr, new MessagePostProcessor(){
public Message postProcessMessage(Message message)
throws JMSException {
message.setJMSExpiration(System.currentTimeMillis()+60*60*1000);
message.setIntProperty("level", 2);
return message;
}
});
}
}
Sender.java
package cn.com.snt.async_jms;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Sender {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("cn/com/snt/async_jms/applicationContext-sender.xml");
MessageSender sender=(MessageSender)ctx.getBean("messageSender");
User usr=new User();
usr.setUsername("TOM");
usr.setUserpwd("123");
sender.sendUserMessage(usr);
}
}
applicationContext-sender.xml
<? xml version = "1.0" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:amq = "http://activemq.org/config/1.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.org/config/1.0 http://people.apache.org/repository/org.apache.activemq/xsds/activemq-core-4.1-incubator-SNAPSHOT.xsd" >
< bean id = "connectionFactory" class = "org.apache.activemq.pool.PooledConnectionFactory" >
< property name = "connectionFactory" >
< bean class = "org.apache.activemq.ActiveMQConnectionFactory" >
< property name = "brokerURL" value = "tcp://localhost:61616" />
</ bean >
</ property >
</ bean >
< bean id = "jmsTemplate" class = "org.springframework.jms.core.JmsTemplate" >
< property name = "connectionFactory" ref = "connectionFactory" />
< property name = "defaultDestinationName" value = "userMsgQ" />
<property name="pubSubDomain" value="true"/>
</ bean >
< bean id = "messageSender" class = "cn.com.snt.async_jms.MessageSender" >
< property name = "jmsTemplate" ref = "jmsTemplate" />
</ bean >
</ beans >
红色的部分 ,pubSubDomain=true, 表示发送 Pub/Sub 域消息 , 些地址解析器 DestinationResolver 会将字符串解析成 Topic 类型的地址