在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>
<?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
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" class="org.springframework.jndi.JndiTemplate">
- <property name="environment">
- <props>
- <prop key="java.naming.factory.initial">
- org.apache.activemq.jndi.ActiveMQInitialContextFactory</prop>
- <prop key="java.naming.provider.url">tcp://localhost:61616</prop>
- <prop key="java.naming.security.principal">system</prop>
- <prop key="java.naming.security.credentials">manager</prop>
- </props>
- </property>
- </bean>
- <bean id="jndiQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
- <property name="jndiTemplate" ref="jndiTemplate"/>
- <property name="jndiName" value="QueueCF"/>
- </bean>
- <bean id="queueConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
- <property name="targetConnectionFactory" ref="jndiQueueConnectionFactory"/>
- <property name="sessionCacheSize" value="1"/>
- </bean>
- <bean id="queueDestination"
- class="org.springframework.jndi.JndiObjectFactoryBean">
- <property name="jndiTemplate" ref="jndiTemplate"/>
- <property name="jndiName" value="queue1"/>
- </bean>
- <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
- <property name="connectionFactory" ref="queueConnectionFactory"/>
- <property name="defaultDestinationName" value="queue1"/>
- <property name="pubSubDomain" value="false"/>
- </bean>
- <bean id="jmsSender" class="com.jms.client.JMSSender">
- <property name="jmsTemplate" ref="jmsTemplate"/>
- <property name="queueName" value="queue1"/>
- </bean>
- </beans>
<?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" class="org.springframework.jndi.JndiTemplate"> <property name="environment"> <props> <prop key="java.naming.factory.initial"> org.apache.activemq.jndi.ActiveMQInitialContextFactory</prop> <prop key="java.naming.provider.url">tcp://localhost:61616</prop> <prop key="java.naming.security.principal">system</prop> <prop key="java.naming.security.credentials">manager</prop> </props> </property> </bean> <bean id="jndiQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate" ref="jndiTemplate"/> <property name="jndiName" value="QueueCF"/> </bean> <bean id="queueConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="targetConnectionFactory" ref="jndiQueueConnectionFactory"/> <property name="sessionCacheSize" value="1"/> </bean> <bean id="queueDestination" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate" ref="jndiTemplate"/> <property name="jndiName" value="queue1"/> </bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="queueConnectionFactory"/> <property name="defaultDestinationName" value="queue1"/> <property name="pubSubDomain" value="false"/> </bean> <bean id="jmsSender" class="com.jms.client.JMSSender"> <property name="jmsTemplate" 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();
- }
- }
- }
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;
- }
- }
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();
- }
- }
- }
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依然会出错。