JMS与Spring之一(用JmsTemplate同步收发消息)
在Spring框架中使用JMS传递消息有两种方式:JMS template和message listener container,前者用于同步收发消息,后者用于异步收发消息。
本文主要讲述用JMS template同步收发消息。
1.?????? JMS template综述
使用JmsTemplate收发消息可以显著减少开发的精力投入。使用JmsTemplate时,不需要费心考虑连接到JMS provider(如ActiveMQ),建立JMS Session(如QueueSession),建立消息生产者(如QueueSender),甚至不用新建一个JMS消息(如TextMessage)。JmsTemplate能够自动将各种类型如String、Byte[]等转换为响应的JMS消息对象类型,当然也可以自己写Converter转换复杂的消息。
JmsTemplate常用的方法有send、convertAndSend、receive和convertAndReceive。
2.?????? 详细步骤
下面通过一个例子详细讲解使用JmsTemplate同步收发消息。
(1)?????? 环境
JMS1.1;apache-activemq-5.4.0;Spring-2.5.4;JDK-1.5;myeclipse7.5
(2)?????? 源代码(Java Project)
i)??????????????? 结构

ii)????????????? 源代码
.classpath:
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
???????? <classpathentry kind="src" path="src/main/java"/>
???????? <classpathentry kind="src" path="src/main/resources"/>
???????? <classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
???????? <classpathentry exported="true" kind="lib" path="lib/jms-1.1.jar"/>
???????? <classpathentry exported="true" kind="lib" path="lib/spring.jar"/>
???????? <classpathentry exported="true" kind="lib" path="lib/activemq-all-5.4.0.jar"/>
???????? <classpathentry kind="output" path="bin"/>
</classpath>
jndi.properties:
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager
connectionFactoryNames = QueueCF
queue.queue1 = jms.queue1
app-context.xml:
<?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:jms="http://www.springframework.org/schema/jms"
??? ???xsi:schemaLocation="
?????? http://www.springframework.org/schema/beans spring-beans-2.0.xsd
???????? ?? http://www.springframework.org/schema/jms
???????? ?? http://www.springframework.org/schema/jms/spring-jms-2.5.xsd">
?
???????? <bean id="jndiTemplate" ref="jndiTemplate"/>
?????? <property name="jndiName" value="QueueCF"/>
??? </bean>??
??? <bean id="queueConnectionFactory" ref="jndiQueueConnectionFactory"/>
??????? <property name="sessionCacheSize" value="1"/>
??? </bean>?
???????? <bean id="queueDestination"
???????? ?? ref="jndiTemplate"/>
???????? ?? <property name="jndiName" value="queue1"/>
???????? </bean>?
???????? <bean id="jmsTemplate" ref="queueConnectionFactory"/>
???????? ?? <property name="defaultDestinationName" value="queue1"/>
???????? ?? <property name="pubSubDomain" value="false"/>
???????? </bean>?????????
???????? <bean id="jmsSender" ref="jmsTemplate"/>
???????? ?? <property name="queueName" value="queue1"/>
???????? </bean>?
</beans>
JMSReceiverSync.java:
package com.jms.server;?
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
?
public class JMSReceiverSync {?
???????? public static void main(String[] args) {??????????????????
?????????????????? try {
??????????????????????????? ApplicationContext ctx =
???????????????????????????????????? new ClassPathXmlApplicationContext("app-context.xml");
??????????????????????????? JmsTemplate jmsTemplate = (JmsTemplate)ctx.getBean("jmsTemplate");?
??????????????????????????? int counter = 0;
??????????????????????????? while(counter < 10) {
???????? ??????? ?? Object msg = jmsTemplate.receiveAndConvert();
???????? ??????? ?? if (msg instanceof String) {
???????? ??????? ??????????? System.out.println("Received: " + msg);
???????? ??????? ?? }
???????? ??????? ?? counter++;
??????????????????????????? }???????????????????????????
??????????????????????????? System.exit(0);
?????????????????? } catch (Exception up) {
??????????????????????????? up.printStackTrace();
?????????????????? }
???????? }
}
JMSSender.java:
package com.jms.client;?
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;?
public class JMSSender {?
???????? public void sendMessage() throws Exception {?
?????????????????? MessageCreator msg = new MessageCreator() {
??????????????????????????? public Message createMessage(Session session)throws JMSException {
???????????????????????????????????? TextMessage msg = session.createTextMessage("TEST 1");
???????? ????????? ?????? return msg;
???????? ??????? }
?????????????????? };???????????????????????????
?????????????????? jmsTemplate.send(queueName, msg);
?????????????????? System.out.println("Message Sent...");??????? ????????????????????????
???????? }
?
???????? public JmsTemplate jmsTemplate = null;
???????? public String queueName = null;????????
???????? public void setJmsTemplate(JmsTemplate jmsTemplate) {
?????????????????? this.jmsTemplate = jmsTemplate;
???????? }????????
???????? public void setQueueName(String queueName) {
?????????????????? this.queueName = queueName;
???????? }
}
JMSSenderApp.java:
package com.jms.client;?
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;?
public class JMSSenderApp {?
???????? public static void main(String[] args) {??????????????????
???????? ??? try {
??????????????????????????? ApplicationContext ctx =
???????????????????????????????????? new ClassPathXmlApplicationContext("app-context.xml");
??????????????????????????? JMSSender jmsSender = (JMSSender)ctx.getBean("jmsSender");
??????????????????????????? jmsSender.sendMessage();
???????? ??? System.exit(0);
???????? ??? } catch (Exception exception) {
???????? ??????? exception.printStackTrace();
???????? ??? }
???????? }??????
}?
(3)?????? 说明
可以看到,用JmsTemplate收发消息非常简单,因为JmsTemplate几乎帮我们做了大多数的工作,相关关系如下图所示(可结合app-context.xml理解):

??? 步骤与不使用Spring相似,只是都是通过配置完成的。
3.?????? 疑惑
明明用app-context.xml就包含所有的上下文信息了,可是删掉jndi.properties依然会出错。