在EJB世界里,JMS消息最常用的功能之一是用于实现消息驱动Bean(MDB)。Spring提供了一个方法来创建消息驱动的POJO(MDP),并且不会把用户绑定在某个EJB容器上。
通常用消息监听器容器从JMS消息队列接收消息并驱动被注射进来的MDP。消息监听器容器负责消息接收的多线程处理并分发到各MDP中。一个消息侦听容器是MDP和消息提供者之间的一个中介,用来处理消息接收的注册,事务管理的参与,资源获取和释放,异常转换等等。这使得应用开发人员可以专注于开发和接收消息(可能的响应)相关的(复杂)业务逻辑,把和JMS基础框架有关的样板化的部分委托给框架处理。
1.SimpleMessageListenerContainer
这个消息侦听容器是三种中最简单的。它在启动时创建固定数量的JMS session并在容器的整个生命周期中使用它们。这个类不能动态的适应运行时的要求或参与消息接收的事务处理。然而它对JMS提供者的要求也最低。它只需要简单的JMS API。
2.DefaultMessageListenerContainer
这个消息侦听器使用的最多。和 SimpleMessageListenerContainer 相反,这个子类可以动态适应运行时侯的要求,也可以参与事务管理。每个收到的消息都注册到一个XA事务中(如果使用 JtaTransactionManager 配置过),这样就可以利用XA事务语义的优势了。这个类在对JMS提供者的低要求和提供包括事务参于等的强大功能上取得了很好的平衡。
3.ServerSessionMessageListenerContainer
这个监听器容器利用JMS ServerSessionPool SPI动态管理JMS Session。 使用者各种消息监听器可以获得运行时动态调优功能,但是这也要求JMS提供者支持ServerSessionPool SPI。如果不需要运行时性能调整,请使用 DefaultMessageListenerContainer 或 SimpleMessageListenerContainer。
在activemq与spring整合时JMS规范的ack消息确认机制有一下四种,定于在session对象中:
如果想设置ack消息确认机制为客户端手动确认,在spring总配置消费者监听器的时候,设置sessionAcknowledgeMode的值为代码如下:
但这样设置是无效的,请看spring类org.springframework.jms.listener.AbstractMessageListenerContainer的一段源码:
protected void commitIfNecessary(Session session, Message message) throws JMSException {
// Commit session or acknowledge message.
if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(session);
}
}
else if (message != null && isClientAcknowledge(session)) {
message.acknowledge();
}
}
protected boolean isClientAcknowledge(Session session) throws JMSException {
return (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
}
当设置sessionAcknowledgeMode为2时,虽然是客户端手动确认,但是却被spring自动确认了,造成设置无效。这时只需要把sessionAcknowledgeMode的值设置成activemq自定义的类型INDIVIDUAL_ACKNOWLEDGE = 4即可。
1、spring配置文件
2、自定义消息监听器代码
package com.hern.avtivemq;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@Component("myMessageListener")
public class MyMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
if (message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("监听器接受内容是:" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
3、生产者
package com.hern.avtivemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
/*
* 消息生产者
* */
@Service
public class SpringMQ_Produce {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");
SpringMQ_Produce springMQ_produce = (SpringMQ_Produce) applicationContext.getBean("springMQ_Produce");
//发送消息
springMQ_produce.jmsTemplate.send(session -> {
TextMessage textMessage = session.createTextMessage("---Spring整合ActiveMQ---");
System.out.println("发送的消息内容是:" + textMessage.getText());
return textMessage;
});
System.out.println("发送结束");
}
}
4、 消费者
package com.hern.avtivemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
/*
* 消息消费者
* */
@Service
public class SpringMQ_Consume {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");
SpringMQ_Consume springMQ_consume = (SpringMQ_Consume) applicationContext.getBean("springMQ_Consume");
//接收消息
String result = (String) springMQ_consume.jmsTemplate.receiveAndConvert();
System.out.println("接收的消息是:" + result);
}
}