`

7.4使用Spring编写JMS客户端

阅读更多
ActiveMQ使用Spring框架来ease client-to-broker交互的许多方面,但是Spring框架使用它的API和为JMS特意设计的容器能更进一步。相辅相成,ActiveMQ和Spring构建了一个excellent的JMS开发平台,是许多通常性的任务能极容易地完成。一些任务会在该节中被讨论到,包括:
■配置JMS连接--ActiveMQ提供类用作配置URLs和其他连接到代理的参数。连接工厂能稍后被你的程序用来获取合适的连接。
■配置JMS destination--ActiveMQ destination对象能简单地进行配置,它简单地作为beans,代表用于你的producers和consumers的JMS destinations。
■定义JMS consumers--Spring提供helper类允许你简单地配置消息监听容器并hook消息监听器到它。
■实现JMSproducers--Spring也为建立新的producers提供helper bean classes。
在下面的章节中,这个任务将被演示并且portfolio应用将被修改为使用ActiveMQ和Spring整合的所有优点。
7.4.1配置JMS连接
如前面示例所看到的,创建JMS应用的第一步是创建到ActiveMQ代理的连接。ActiveMQConnectionFactory是建立ActiveMQConnection的工厂,它们都能在Spring中简单的使用。下面的snippet显示了如何使用Spring XML配置定义ActiveMQConnectionFactory:
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
  <property name="brokerURL" value="tcp://localhost:61616" />
  <property name="userName" value="admin" />
  <property name="password" value="password" />
</bean>

在这个snippet中,注意在ActiveMQConnectionFactory上配置的属性。
在一些使用示例中为了达到想要的效果a pool of connnections是必要的。为了这个目的,ActiveMQ提供了PooledConnectionFactory类,它报刊了一个JMS连接和sessions池。这里有一个PooledConnectionFactory的Spring XML配置:
<bean id="pooledJmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
  <property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
在这个示例中只有一个属性在PooledConnectionFactory上被配置--connectionFactory属性。connectionFactory属性配用来定义到ActiveMQ代理的underlying连接工厂,这个连接工厂将被pooled connection factory。在这个用例中,我们使用了我们先前定义的jmsConnectionFactory bean。
因为pooled connection factory在Apache Commons Pool project(http://mng.bz/j3PV)上有一个依赖,即将需要添加JAR到claspath。或者,如果你为你的项目管理使用Maven,只要添加下面的dependency到pom.xml文件:
<dependency>
  <groupId>commons-pool</groupId>
  <artifactId>commons-pool</artifactId>
  <version>1.4</version>
</dependency>

先前的XML定义关于common-pool-1.4.jar 文件的Maven依赖,并且为你自动获取。
一旦JMS连接被定义,你能进一步到定义JMSdestinations,producers,和consumers。
7.4.2配置JMS destinations
JMS destinations能用ActiveMQTopic和ActiveMQQueue类在activemq.xml文件中预定义。下面的snippet包含了用于portfolio示例的两个新的topic定义:
<bean id="cscoDest" class="org.apache.activemq.command.ActiveMQTopic">
  <constructor-arg value="STOCKS.CSCO" />
</bean>
<bean id="orclDest" class="org.apache.activemq.command.ActiveMQTopic">
  <constructor-arg value="STOCKS.ORCL" />
</bean>

如你所见,这些类为在ActiveMQTopic类上设置一个想要的destination name使用constructor injection。预定义的topics在ActiveMQ是不需要的,但它对环境是便利的,在环境中代理需要客户端为许多操作进行身份验证。更多关于client authentication信息请看第6章。现在一个连接和一系列的destinations已经存在了,你能开始发送和接收消息了。
7.4.3建立JMS consumers
下面的两节touch upon Spring JMS(http://mng.bz/I0Pe) 为建立consumers和producers的基本使用,因为它使建立JMSconsumers和producers极度简单。虽然Spring JMS提供了一些强大的特性,但是这两节将不深入详细,因为这在本书的讨论范围之外。取而代之地,我们将展示使你快速上手和运行于portfolio示例的方面。关于Spring JMS的更多信息,请查阅Spring文档。
在Spring中接收消息的基本的abstraction是消息监听容器(MLC: see http://mng.bz/LJti)。MLC设计提供了一个在你消息监听和代理间处理connections,threading的媒介,使你仅仅要关心你的在监听器上的业务逻辑。在下面的列表中,从第3章来的portfolio 消息监听被用于两个消息监听容器,为两个在先前章节定义的destinations。
Listing 7.22 Defining two Spring message listener containers and a message listener
<!-- The message listener -->
<bean id="portfolioListener"
class="org.apache.activemq.book.ch3.portfolio.Listener">
</bean>
<!-- Spring DMLC -->
<bean id="cscoConsumer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
  <property name="connectionFactory" ref="jmsConnectionFactory" />
  <property name="destination" ref="cscoDest" />
  <property name="messageListener" ref="portfolioListener" />
</bean>
<!-- Spring DMLC -->
<bean id="orclConsumer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
  <property name="connectionFactory" ref="jmsConnectionFactory" />
  <property name="destination" ref="orclDest" />
  <property name="messageListener" ref="portfolioListener" />
</bean>

在表7.22中的每个MLC实例需要一个连接工厂,一个destination和一个消息监听。所以你所要做的是实现一个消息监听bean并让其他事情交由Spring MLC做。注意在这个示例中我们使用了plain(not pooled)连接工厂。这是因为对于简单的示例connection pooling是不需要的。这个示例使用了Spring DefaultMessageListenerContainer(DMLC),它在MLC中是最普遍使用的。虽然在DMLC上许多其他的属性能被配置,但这个示例仅使用基本的。当这两个DMLC实例被启动,他们将准备好接收消息并转换到消息监听。
现在让我们发送消息到ActiveMQ。
7.4.4建立JMS producers
正如接收消息的示例,Spring也提供发送消息的便利。发送消息的creucial abstraction是Spring的JmsTemplate类。JmsTemplate遵照基本模板模式为发送消息提供方便的类。
使用Spring发送消息的一个最普遍的方法是通过实现Spring MessageCreator接口和使用它 with the appropriate send() method of the JmsTemplate class。下面列表通过借用第三章的stock portfolio publisher 实现整个消息建立逻辑展示了它。
Listing 7.23 Implementation of a MessageCreator for sending messages using Spring
public class StockMessageCreator implements MessageCreator {
	private int MAX_DELTA_PERCENT = 1;
	private Map<Destination, Double> LAST_PRICES = new Hashtable<Destination, Double>();
	Destination stock;
	public StockMessageCreator(Destination stock) {
		this.stock = stock;
	}
	public Message createMessage(Session session) throws JMSException {
		Double value = LAST_PRICES.get(stock);
		if (value == null) {
			value = new Double(Math.random() * 100);
		}
		// lets mutate the value by some percentage
		double oldPrice = value.doubleValue();
		value = new Double(mutatePrice(oldPrice));
		LAST_PRICES.put(stock, value);
		double price = value.doubleValue();
		double offer = price * 1.001;
		boolean up = (price > oldPrice);
		MapMessage message = session.createMapMessage();
		message.setString("stock", stock.toString());
		message.setDouble("price", price);
		message.setDouble("offer", offer);
		message.setBoolean("up", up);
		System.out.println(
			"Sending: " + ((ActiveMQMapMessage)message).getContentMap()
			+ " on destination: " + stock
		);
		return message;
	}
	protected double mutatePrice(double price) {
		double percentChange = (2 * Math.random() * MAX_DELTA_PERCENT) - MAX_DELTA_PERCENT;
		return price * (100 + percentChange) / 100;
	}
}

MessageCreator接口仅定义了createMessage()方法,它将返回一个JMS消息。这里,我们为了建立随机stock 价格实现了一些逻辑,并且women建立了一个合适的JMS map message来hold所有的相关了的数据。为了发送消息,JmsTemplate’s send()方法将使用StockMessageCreator如下所示。
Listing 7.24 JMS publisher implementation in Spring
public class SpringPublisher {
	private JmsTemplate template;
	private int count = 10;
	private int total;
	private Destination[] destinations;
	private HashMap<Destination,StockMessageCreator> creators = new HashMap<Destination,StockMessageCreator>();
	public void start() {
		while (total < 1000) {
			for (int i = 0; i < count; i++) {
				sendMessage();
			}
			total += count;
			System.out.println("Published '" + count + "' of '" + total + "' price messages");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException x) {
			}
		}
	}
	protected void sendMessage() {
		int idx = 0;
		while (true) {
			idx = (int)Math.round(destinations.length * Math.random());
			if (idx < destinations.length) {
				break;
			}
		}
		Destination destination = destinations[idx];
		template.send(destination, getStockMessageCreator(destination));
	}
	private StockMessageCreator getStockMessageCreator(Destination dest) {
		if (creators.containsKey(dest)) {
			return creators.get(dest);
		} else {
			StockMessageCreator creator = new StockMessageCreator(dest);
			creators.put(dest, creator);
			return creator;
		}
	}
	// getters and setters goes here
}

在表7.24中要注意的重要是send()方法如何使用message creator。在这个示例中的其他部分是和第三章中的原始的stock portfolio publisher相同的。现在你有了使用Spring发布消息到ActiveMQ的所有必要的组件。所有剩下的工作是正确地配置它,如下表所示。
Listing 7.25 JMS publisher configuration in Spring
<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
	<property name="connectionFactory" ref="pooledJmsConnectionFactory" />
</bean>
<bean id="stockPublisher" class="org.apache.activemq.book.ch7.spring.SpringPublisher">
	<property name="template" ref="jmsTemplate" />
	<property name="destinations">
		<list>
			<ref local="cscoDest" />
			<ref local="orclDest" />
		</list>
	</property>
</bean>

在表7.25中的snippet展示了Spring JmsTemplate和publisher的实例。publisher简单地需要一个正在使用的JMS destination的引用,并且JmsTemplate需要一个connection工厂。
注意:

The pooled connection factory is used with the JmsTemplate.这是很重要的因为JmsTemplate是为use with Java EE containers in mind 设计的,它按照Java EE 规范代表性地提供connection pooling 能力。每一个对JmsTemplate.send()的调用建立和销毁所有的JMS资源(connections,consumers和producers)。所以如果你不在使用Java EE container,确保为sending message with the JmsTemplate使用一个pooled connection工厂.

connections和destinations被定义了;consumers和producer已经建立。现在让我们运行示例。
7.4.5组装在一起
在实现了这个示例的所有部分之后,应用已经准备好运行了。看看下面的列表来看看将助兴示例的main方法。
Listing 7.26 The main method for the Spring example
public class SpringClient {
	public static void main(String[] args) {
		BrokerService broker = new BrokerService();
		broker.addConnector("tcp://localhost:61616");
		broker.setPersistent(false);
		broker.start();
		FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
			"src/main/resources/org/apache/activemq/book/ch7/spring-client.xml"
		);
		SpringPublisher publisher = (SpringPublisher)context.getBean("stockPublisher");
		publisher.start();
	}
}

这个简单类启动了一个最小化的ActiveMQ代理配置和初始化了Spring application contex 去启动JMS客户端。
这个示例能使用下面的命令运行。
Listing 7.27 Run the Spring example
$ mvn exec:java \
-Dexec.mainClass=org.apache.activemq.book.ch7.spring.SpringClient \
-Dlog4j.configuration=file:src/main/java/log4j.properties
...
Sending: {price=65.958996694, stock=CSCO, offer=66.0249556914, up=false}
on destination: topic://STOCKS.CSCO
topic://STOCKS.IONA 79.97 80.05 down
Sending: {price=80.67595675108, stock=ORCL, offer=80.7566327078, up=true}
on destination: topic://STOCKS.ORCL
topic://STOCKS.JAVA 65.96 66.02 down
Sending: {price=65.63333898492, stock=CSCO, offer=65.69897232391, up=false}
on destination: topic://STOCKS.CSCO
topic://STOCKS.IONA 80.68 80.76 up
Sending: {price=80.50525969261, stock=ORCL, offer=80.58576495231, up=false}
on destination: topic://STOCKS.ORCL
topic://STOCKS.JAVA 65.63 65.70 down
Sending: {price=81.2186806051, stock=ORCL, offer=81.29989928577, up=true}
on destination: topic://STOCKS.ORCL
topic://STOCKS.IONA 80.51 80.59 down
Sending: {price=65.48960846536, stock=CSCO, offer=65.5550980738, up=false}
on destination: topic://CSCO
topic://STOCKS.IONA 81.22 81.30 up
topic://STOCKS.JAVA 65.49 65.56 down
...

如你所见,producer和consumer都打印他们的消息到基本output,如示例所运行的。
在该节,你使用了Spring来augment从第3章来的stock portfolio的示例程序。你能重新使用大部分的原始逻辑,但是这次你使用一些Spring来大大简化了示例。如前面陈述的,这个示例简单的touched on使用Spring JMS最基本的东西。如果你想知道关于Spring JMS的更多信息,请看相关文档(http://mng.bz/I0Pe)。
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Spring in Action(第二版 中文高清版).part2

    10.2 协同使用JMS和Spring 10.2.1 处理冗长失控的JMS代码 10.2.2 使用JMS模板 10.2.3 转换消息 10.2.4 将Spring的网关支持类应用于JMS 10.3 创建消息驱动POJO 10.3.1 创建消息监听器 10.3.2 编写纯POJO MDP ...

    Spring in Action(第二版 中文高清版).part1

    10.2 协同使用JMS和Spring 10.2.1 处理冗长失控的JMS代码 10.2.2 使用JMS模板 10.2.3 转换消息 10.2.4 将Spring的网关支持类应用于JMS 10.3 创建消息驱动POJO 10.3.1 创建消息监听器 10.3.2 编写纯POJO MDP ...

    Spring in Action(第2版)中文版

    10.2协同使用jms和spring 10.2.1处理冗长失控的jms代码 10.2.2使用jms模板 10.2.3转换消息 10.2.4将spring的网关支持类应用于jms 10.3创建消息驱动pojo 10.3.1创建消息监听器 10.3.2编写纯pojomdp 10.4使用...

    Spring-Reference_zh_CN(Spring中文参考手册)

    7.4. Spring里的advisor(Advisor) API 7.5. 使用ProxyFactoryBean创建AOP代理 7.5.1. 基础 7.5.2. JavaBean属性 7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    Spring 2.0 开发参考手册

    19.2. 使用Spring JMS 19.2.1. JmsTemplate 19.2.2. 连接工厂 19.2.3. (消息)目的地管理 19.2.4. 消息侦听容器 19.2.5. 事务管理 19.3. 发送一条消息 19.3.1. 使用消息转换器 19.3.2. SessionCallback 和...

    Spring中文帮助文档

    7.4. Spring里的Advisor API 7.5. 使用ProxyFactoryBean创建AOP代理 7.5.1. 基础 7.5.2. JavaBean属性 7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”通知器 ...

    Spring API

    7.4. Spring里的Advisor API 7.5. 使用ProxyFactoryBean创建AOP代理 7.5.1. 基础 7.5.2. JavaBean属性 7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”通知器 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    spring chm文档

    Spring Framework 开发参考手册 Rod Johnson Juergen Hoeller Alef Arendsen Colin Sampaleanu Rob Harrop Thomas Risberg Darren Davison Dmitriy Kopylenko Mark Pollack ...19.2. 使用Spring JMS ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    《程序天下:J2EE整合详解与典型案例》光盘源码

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    JBoss Seam 工作原理、seam和hibernate的范例、RESTFul的seam、seam-gen起步、seam组件、配置组件、jsf,jboss、标签、PDF、注解等等

    Seam - 语境相关的组件[满江红20071230]............................................................................................................................ 1 Java EE 框架...........................

Global site tag (gtag.js) - Google Analytics