Spring 2.0 的 JMS 改进

工程 | Ben Hale | 2006 年 4 月 9 日 | ...

随着 Spring 1.1 的发布,Spring 社区首次体验到了 JMS 支持。 此支持包括异常转换、消息转换以及类似于 JdbcTemplate 的模板类。此支持还处理了 JMS 1.0.2 和 1.1 规范之间的域统一。 此支持的核心是 JmsTemplate 类及其 JMS 1.0.2 对应类 JmsTemplate102

与使用原始 JMS API 进行企业消息传递相比,此支持是一项重大改进。 但是,它确实存在一个缺点; JmsTemplate 仅支持使用 JmsTemplate.receive() 方法同步接收消息。 这种行为对很多人来说都很好用,但绝大多数用户最终都会推出自己的异步使用者实现。 简而言之,他们想要 EJB 2 所谓的 消息驱动 Bean

用户无需再这样做了。 随着 2.0M1 的发布以及稍后发布的最终 2.0 版本,已添加对 JMS 消息异步接收的本机支持。 JmsTemplate 仍然用于发送消息,但现在它已经加入了 AbstractMessageListenerContainer 的子类,例如 DefaultMessageListenerContainerSimpleMessageListenerContainerServerSessionMessageListener

让我们来看看如何使用这些 MessageListenerContainers。 第一步是创建一个可以接收消息的类。 为此,必须创建一个实现 MessageListener 接口的类。


package jmsexample;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class ExampleListener implements MessageListener {

	public void onMessage(Message message) {
		if (message instanceof TextMessage) {
			try {
				System.out.println(((TextMessage)message).getText());
			} catch (JMSException e) {
				throw new RuntimeException(e);
			}
		} else {
			throw new IllegalArgumentException(
					"Message must be of type TestMessage");
		}
	}

}

一旦你有了它,你需要一个消息生产者。 此代码与 Spring 2.0 之前的代码相同,因此如果你已经有执行此操作的代码,则无需进行任何更改。


package jmsexample;

import org.springframework.jms.core.JmsTemplate;

public class ExampleProducer {

	private JmsTemplate jmsTemplate;

	public ExampleProducer(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	public void sendMessage() {
		jmsTemplate.convertAndSend("Example Message");
	}

}

接下来,你需要配置你的上下文以创建一个将消息路由到此 bean 的 MessageListenerContainer。 你会注意到我在这个例子中使用了 ActiveMQ 实现类。 这恰好是许多 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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="messageListener" class="jmsexample.ExampleListener" />

	<bean id="messageProducer" class="jmsexample.ExampleProducer">
		<constructor-arg ref="jmsTemplate" />
	</bean>

	<bean id="jmsTemplate"
		class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="defaultDestination" ref="destination" />
	</bean>

	<bean id="destination" class="org.activemq.message.ActiveMQQueue">
		<constructor-arg value="jmsExample" />
	</bean>

	<bean id="listenerContainer"
		class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="destination" />
		<property name="messageListener" ref="messageListener" />
	</bean>

	<bean id="connectionFactory"
		class="org.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="tcp://localhost:61616" />
	</bean>

</beans>

我暂时跳过它,但显然你需要启动一个 MQ,并启动一个引导你的上下文的 main 方法。 我已经添加了一个 此项目的存档,这样你就可以看到其余的代码,如果你需要它。

最后,你只需要运行你的应用程序并查看输出。

Example Message

需要注意的一件事是,到目前为止,我们一直在使用单个使用者线程进行异步接收。 可以使用 MessageListenerContainer 的并发使用者属性将你的使用者进行多线程处理(请记住,你仍然需要使它们无状态或线程安全)。


<bean id="listenerContainer"
	class="org.springframework.jms.listener.DefaultMessageListenerContainer">
	<property name="concurrentConsumers" value="5" />
	<property name="connectionFactory" ref="connectionFactory" />
	<property name="destination" ref="destination" />
	<property name="messageListener" ref="messageListener" />
</bean>

我想指出的一件事(来自我自己的痛苦经历)是确保你不要将并发使用者与 Topic 一起使用。 请记住,在 JMS 主题中,所有消息都会传递到主题上的所有使用者。 这意味着,如果你在一个主题上具有并发使用者,则所有使用者都将收到相同的消息; 通常是你想要避免的事情。 但是,如果你正在使用队列,显然这会将每个新消息以循环方式分发给使用者。

所以,你已经得到了它。 它不是很华丽,并且可能非常类似于你可能在某个时候编写的东西,但是现在你所要做的就是使用它,你无需维护它。 我还要说这只是冰山一角。 MessageListenerContainers 能够参与事务,使用自定义线程池(例如应用程序服务器提供的线程池)以及新的 Spring TaskExecutor 抽象,甚至向使用者公开本机 JMS 会话。 这些都是另一篇文章的主题。

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速你的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部