1.1 JMS简介
JMS的全称是Java Message Service,即Java消息服务。它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中的话我们可以在特定的时候利用生产者生成一消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。对于消息的传递有两种类型,一种是点对点的,即一个生产者和一个消费者一一对应;另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
1.2 Spring整合JMS
对JMS做了一个简要介绍之后,接下来就讲一下Spring整合JMS的具体过程。JMS只是一个标准,真正在使用它的时候我们需要有它的具体实现,这里我们就使用Weblogic的Weblogic JMS来作为它的实现。首先我们需要搭建一个Spring框架,并引用操作Weblogic JMS所需要的jar包。搭建Spring框架可以参考博客:https://blog.csdn.net/qq_36769100/article/details/70908148 ,Spirng框架依赖jar包下载地址:https://download.csdn.net/download/u013310119/10311191 。操作Weblogic JMS所需要的jar包下载地址为:https://download.csdn.net/download/u013310119/10311218 。搭建完成Spring框架,把Weblogic JMS的jar包导入后,就可以进行,Spring整合Weblogic JMS的开发。
在applicationContext.xml中配置Weblogic 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" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
<bean id="weblogicJms" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
weblogic.jndi.WLInitialContextFactory
</prop>
<prop key="java.naming.provider.url">
t3://10.19.22.94:7011
</prop>
<prop key="java.naming.factory.url.pkgs">
weblogic.jndi.factories
</prop>
<prop key="java.naming.security.principal"> <!--用户名 -->
weblogic
</prop>
<prop key="java.naming.security.credentials"> <!--密码 -->
weblogic123
</prop>
</props>
</property>
</bean>
<!-- Connection factory -->
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="gt3.esb.jms.con.ESBConnectionFactory" />
<property name="jndiTemplate" ref="weblogicJms"/>
</bean>
<!-- 用来接受消息的消息队列 -->
<bean id="jmsQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="gt3.esb.jms.mdb.BaseQueueAsynMDBean" />
<property name="jndiTemplate" ref="weblogicJms"/>
<!-- <delivery-params-overrides>
<priority>9</priority>优先级,0最小,9最大
</delivery-params-overrides>
批量还是实时,0为实时,25,75,100为批量
<messaging-performance-preference>0</messaging-performance-preference> -->
</bean>
<!-- 用来测试消息回复的 -->
<bean id="responseQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="responseQueue" />
<property name="jndiTemplate" ref="weblogicJms"/>
</bean>
<!-- Receiver --> <!--消息消费者 -->
<!-- <bean id="jmsReceiver" class="com.inspur.JMS.service.QueueMsgReceiver1">
</bean> -->
<bean id="jmsReceiverJDBC" class="com.inspur.JDBCTemplate.listener.ConsumerMessageListener">
</bean>
<bean id="jmsReceiverRsponse" class="com.inspur.JMS.service.ConsumerMessageListener">
</bean>
<!-- Message Listener -->
<!-- 在Spring整合JMS的应用中,如果我们要进行本地的事务管理的话非常简单,只需要在定义对应的消息监听容器时
指定其sessionTransacted属性为true,如: <property name="sessionTransacted" value="true"/> 该属性值默认为false,
这样JMS在进行消息监听的时候就会进行事务控制,
当在接收消息时监听器执行失败时JMS就会对接收到的消息进行回滚-->
<!-- 如果想接收消息和数据库访问处于同一事务中,那么我们就可以配置一个外部的事务管理同时配置一个支持外部事务管理的消息监听容器
(如DefaultMessageListenerContainer)。要配置这样一个参与分布式事务管理的消息监听容器,
我们可以配置一个JtaTransactionManager,当然底层的JMS ConnectionFactory需要能够支持分布式事务管理,
并正确地注册我们的JtaTransactionManager。这样消息监听器进行消息接收和对应的数据库访问就会处于同一数据库控制下,
当消息接收失败或数据库访问失败都会进行事务回滚操作。当给消息监听容器指定了transactionManager时,
消息监听容器将忽略sessionTransacted的值。 -->
<bean id="listenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="destination" ref="jmsQueue"/>
<!-- <property name="messageListener" ref="jmsReceiver"/> -->
<property name="messageListener" ref="jmsReceiverRsponse"/>
<!-- <property name="transactionManager" ref="jtaTransactionManager"/> -->
<property name="autoStartup" value="true"/>
<!-- 设置固定的线程数 -->
<property name="concurrentConsumers" value="6"></property>
<!-- 设置动态的线程数 -->
<property name="concurrency" value="2-9"></property>
<!-- 设置最大的线程数 -->
<property name="maxConcurrentConsumers" value="15"></property>
</bean>
<!-- <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<tx:annotation-driven transaction-manager="jtaTransactionManager"/> -->
<!-- Spring JMS Template --> <!--Spring提供了专门的jmsTemplate对消息队列进行操作-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" lazy-init="true">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="defaultDestination" ref="jmsQueue" />
<property name="receiveTimeout">
<value>5000</value>
</property>
</bean>
<!-- Sender --> <!--生产者-->
<bean id="jmsSender" class="com.inspur.JMS.controller.SendJMSMessage"
lazy-init="true">
<property name="jmsTemplate" ref="jmsTemplate"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 数据源配置 -->
<!-- <jee:jndi-lookup jndi-name="JDBC Data Source-0" id="dataSource"/> -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@10.19.22.91:1521:orcl" />
<property name="username" value="ydpt" />
<property name="password" value="ydpt" />
</bean>
<bean id="Student" class="entity.student">
<property name="name">
<value>Tom</value>
</property>
</bean>
<context:component-scan base-package="com.inspur" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置spring注解扫描的包 -->
<context:component-scan base-package="com.elgin"></context:component-scan>
<!-- 或者不用注解的形式加载bean,改用配置的方式
<bean id="springWebService" class="com.elgin.spring.webservice.SpringWebServiceDemo ">
利用property可以对SpringService类进行初始化,比如<property name="name" value="姚明" /><property name="job" value="职业男篮" />,在配置完SpringService类后,就可以直接在程序中FileSystemXmlApplicationContext类或其他类似功能的类读取applicationContext.xml文件中的内容,并获得SpringService类的对象实例。但现在我们并不这样做,而是将SpringService类发布成WebService。在Tomcat的webapps项目中的WEB-INF\lib目录中有一个axis2-spring-1.4.1.jar文件, 该文件用于将被装配JavaBean的发布成WebService。
-->
</beans>
接着我们来测试一下,看看我们的整合是否真的成功了,测试代码如下:
@Controller
@RequestMapping("test")
public class TestController {
@Autowired
@Qualifier("jmsQueue")
private Destination destination;
@Autowired
private ProducerServiceImpl producerService;
@RequestMapping("first")
public String first() {
producerService.sendMessage(destination, "你好,现在是:" + new Date().toLocaleString());
return null;
}
}
@Component
public class ProducerServiceImpl {
@Autowired
private JmsTemplate jmsTemplate;
public void sendMessage(Destination destination, final String message) {
System.out.println("---------------生产者发送消息-----------------");
System.out.println("---------------生产者发了一个消息:" + message);
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
/*TextMessage textMessage = session.createTextMessage(message);
textMessage.setJMSReplyTo(responseDestination);
return textMessage;*/
return session.createTextMessage(message);
/*MapMessage message = session.createMapMessage();
message.setString("name1", "value1");
message.setString("name2", "value2");
message.setString("name3", "value3");
return message;*/
}
});
}
public void sendMessage(final Destination destination, final Serializable obj) {
//未使用MessageConverter的情况
/*jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
ObjectMessage objMessage = session.createObjectMessage(obj);
return objMessage;
}
});*/
//使用MessageConverter的情况
jmsTemplate.convertAndSend(destination, obj);
jmsTemplate.execute(new SessionCallback<Object>() {
public Object doInJms(Session session) throws JMSException {
MessageProducer producer = session.createProducer(destination);
Message message = session.createObjectMessage(obj);
producer.send(message);
return null;
}
});
jmsTemplate.execute(new ProducerCallback<Object>() {
public Object doInJms(Session session, MessageProducer producer)
throws JMSException {
Message message = session.createObjectMessage(obj);
producer.send(destination, message);
return null;
}
});
}
}
消费者
public class ConsumerMessageListener implements MessageListener {
@Autowired
private TestDao testDao;
private int count = 0;
public void onMessage(Message message) {
//这里我们知道生产者发送的就是一个纯文本消息,所以这里可以直接进行强制转换,或者直接把onMessage方法的参数改成Message的子类TextMessage
System.out.println("在onMessage中线程ID是"+Thread.currentThread());
TextMessage textMsg = (TextMessage) message;
System.out.println(new Date().toLocaleString() + "接收到一个纯文本消息。");
try {
String text = textMsg.getText();
System.out.println("消息内容是:" + text);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
测试结果如下:
下面提供demo源码下载地址:
https://download.csdn.net/download/u013310119/10311333