一、JMS简介
JMS消息可以有效的调动程序中的各种动作,例如,当我们完成一个动作后,我们需要一些程序完成他们自己相应的动作,这时候我们只需要发送一个消息出来,当他们接收到这个消息时,就可以完成自己的事情,是一个很方便的技术,现在用到的JMS消息一般都是通过ActiveMQ来完成,ActIveMQ是一个成熟的框架,可以通过tcp发送JMS,还可以在程序内发送JMS,下面来通过一个实例来介绍。
二、环境搭建
这个实例是在Spring的基础上完成的,所以需要导入spring的所有jar包,当然还需要导入activemq的jar包,下载activemq以后就可以找到一个activemq-all.jar的jar包,导入即可
三、配置文件简介
首先application.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:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 -->
<context:annotation-config />
<context:component-scan base-package="main.java.com"/>
<!-- 激活自动代理功能 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<import resource="jms_client.xml"/>
</beans>
这里的spring就是完成了组件扫描以及aop代理的一些配置,然后就是导入配置activemq的配置文件,如下
<?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:amq="http://activemq.apache.org/schema/core" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 --> <bean id="broker" class="org.apache.activemq.xbean.BrokerFactoryBean"> <property name="config" value="classpath:main/java/conf/ActiveMQConfig.xml" /> <property name="start" value="true" /> </bean> <bean id="myamqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://10.10.11.37:61616"/> <property name="trustedPackages"> <list> <value>main.java</value> </list> </property> </bean> <bean id="myconnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="targetConnectionFactory" ref="myamqConnectionFactory"></property> <property name="sessionCacheSize" value="100" /> </bean> <bean id="myjmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate"> <constructor-arg ref="myconnectionFactory" /> <property name="pubSubDomain" value="false" /> </bean> <bean id="myjmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate"> <constructor-arg ref="myconnectionFactory" /> <property name="pubSubDomain" value="true" /> </bean> </beans>
这里第一步因为不是完整的activemq,是spring嵌入式activemq,所以需要启动一个broker来启动activemq,这里需要用到的是一个另外的activemq配置,内容如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:amq="http://activemq.apache.org/schema/core" 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-3.0.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd"> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" /> <broker useJmx="false" persistent="false" xmlns="http://activemq.apache.org/schema/core"> <transportConnectors> <transportConnector uri="tcp://10.10.11.37:61616"/> </transportConnectors> </broker> </beans>
启动完broker之后就算是完成了acrivemqmq的启动,接下来就开始定义连接工厂了,连接工厂需要制定brokerURL和信任包(不知道有什么卵用),接着就是吧activemq的连接工厂转换成spring的连接工厂,最后两个就不多说了,一个是队列消息templete一个是主题消息template,都是非常简单的,其中如果我们把tcp改为vm则是在程序内发送JMS消息
四、一个服务
在这里我们需要写一个服务用来注册消息监听器,发送消息 , 先把代码贴出来吧
package main.java.com.consumer;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.Topic;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
@Component("msgService")
public class MsgServiceImpl {
//存放注册了的监听器
private Map<String ,Object> consumers = new ConcurrentHashMap<String , Object>();
@Autowired
@Qualifier("myjmsQueueTemplate")
private JmsTemplate queueTemplate ;
@Autowired
@Qualifier("myjmsTopicTemplate")
private JmsTemplate topicTemplate ;
@Autowired
@Qualifier("myconnectionFactory")
private ConnectionFactory connectionFactory ;
public void sendMsg(String destation ,final Serializable message){
if(consumers.containsKey(destation)){
if(consumers.get(destation) instanceof Queue){
queueTemplate.send(destation , new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createObjectMessage(message);
}
});
return ;
}
if(consumers.get(destation) instanceof Topic){
topicTemplate.send(destation , new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createObjectMessage(message);
}
});
}
return ;
}
}
public void registerConsumer(Consumer consumer , JMSConstant type){
try {
Connection connection = connectionFactory.createConnection() ;
connection.start();
Session session = connection.createSession( false, Session.AUTO_ACKNOWLEDGE) ;
if(type != null && type.equals(JMSConstant.TYPE_TOPIC)){
Topic topic = new ActiveMQTopic(consumer.getName()) ;
MessageConsumer messageConsumer = session.createConsumer(topic) ;
messageConsumer.setMessageListener(new JmsMessageListener(consumer));
consumers.put(consumer.getName(), topic) ;
}else{
Queue queue = new ActiveMQQueue(consumer.getName()) ;
MessageConsumer messageConsumer = session.createConsumer(queue) ;
messageConsumer.setMessageListener(new JmsMessageListener(consumer));
consumers.put(consumer.getName(), queue) ;
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
简单说一下吧,首先把这个类注册到spring中,名字为msgService 然后定义一个map来存放目的地,接着就是开始定义的template和从测测提哦你Factory了这些都不多说,都是开始定义了的东西
第一个方法:
sendMsg
可以看到他的参数有两个,一个为目的地,一个为消息内容 ,如果目的地未注册则返回不发送消息,发送消息我们选择发送Object消息,当然所有的Object实例都需要实现Serializable序列化,然后创建消息发送出去
第二个方法
registerConsumer
注册监听器,这里先介绍接口Consumer
package main.java.com.consumer;
import java.io.Serializable;
public interface Consumer {
public String getName() ;
public void onMessage(Serializable msg);
}
所有的监听器都需要实现这个接口,
然后自己定义一个JmsMessageListener :
package main.java.com.consumer;
import java.io.Serializable;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
public class JmsMessageListener implements MessageListener{
private Consumer consumer ;
public JmsMessageListener(Consumer consumer){
this.consumer = consumer ;
}
@Override
public void onMessage(Message msg) {
if(msg != null){
try{
consumer.onMessage(createObjectMsg(msg)) ;
}catch(Exception e){
e.printStackTrace() ;
}
}
}
private Serializable createObjectMsg(Message msg) throws Exception {
Serializable message = ((ObjectMessage) msg).getObject() ;
return message ;
}
}
这个很简单不多说,这是这个服务两个简单必须的方法、
这样我们只需定义一个监听器,
package main.java.com.consumer;
import java.io.Serializable;
public class JmsConsumer1 implements Consumer{
@Override
public String getName() {
return MsgTypeInfo.TEST.name();
}
@Override
public void onMessage(Serializable msg) {
System.out.println("JmsConsumer1 收到 消息 "+ msg);
}
}
然后把它注册到服务,msgService.registerConsumer(new JmsConsumer1(), JMSConstant.TYPE_TOPIC) ;
我们发送一条消息:
msgService.sendMsg(MsgTypeInfo.TEST.name(), "132") ;
就可以看到控制台打印到了接收到的消息。