ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
主要特点:
1. 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
2. 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
3. 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
4. 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
5. 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
6. 支持通过JDBC和journal提供高速的消息持久化
7. 从设计上保证了高性能的集群,客户端-服务器,点对点
8. 支持Ajax
9. 支持与Axis的整合
10. 可以很容易得调用内嵌JMS provider,进行测试
task_dest为发送端的消息队列,接收端监听执行后将执行结果反回给defaultResponseQueue,发送端接收后根据参数保存数据库。两个项目的交互
applicationContext-jms.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd"
default-lazy-init="true">
<bean id="jmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.1.100:61616" />
<property name="closeTimeout" value="60000" />
<!--<property name="userName" value="admin" /> -->
<!--<property name="password" value="admin" /> -->
<!--<property name="optimizeAcknowledge" value="true" /> -->
</bean>
</property>
</bean>
<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref bean="jmsConnectionFactory" />
</property>
</bean>
<!--视频通道:发送消息目的地 -->
<bean id="task_dest" name="task_dest" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0">
<value>task_dest</value>
</constructor-arg>
</bean>
<!-- <bean id="messageConverter" class="com.eciyuanjie.task.jms.converter.ObjectMessageConverter"/> -->
<!--queue通道:消息回复目的地 -->
<bean id="defaultResponseQueue" name="defaultResponseQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0">
<value>defaultResponseQueue</value>
</constructor-arg>
</bean>
<!-- 消息回复监听器 -->
<bean id="defaultResponseListener" class="com.eciyuanjie.task.jms.listener.ResponseListener"/>
<!-- 消息回复监听容器 -->
<bean id="responseListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="destination" ref="defaultResponseQueue" />
<property name="messageListener" ref="defaultResponseListener" />
</bean>
<bean id="jmsServiceImpl" class="com.eciyuanjie.task.jms.service.impl.JmsServiceImpl"></bean>
</beans>
一端只需配置一个发送目的地标签,回复是接收别的项目的回复信息
ResponseListener
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import com.eciyuanjie.task.service.TaskLogService;
public class ResponseListener implements MessageListener {
@Autowired
private TaskLogService taskLogService;
@Override
public void onMessage(Message message) {
if(message instanceof TextMessage){
TextMessage msg = (TextMessage)message;
try {
System.out.println("返回内容:-----------"+msg.getText());
String []args = msg.getText().split("_");
taskLogService.update(Integer.parseInt(args[2]));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
发送代码
((JmsService) ApplicationContextHolder.getBean("jmsServiceImpl")).sendTextMessage(MessageType.task_info, ""+className+"_"+methodName+"_"+taskId);
MessageType是自己定义的枚举
public enum MessageType {task_info
}
发送方法接口
import java.io.Serializable;
import java.util.Map;
import javax.jms.BytesMessage;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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;
import org.springframework.stereotype.Service;
import com.eciyuanjie.task.constants.MessageType;
import com.eciyuanjie.task.jms.service.JmsService;
/**
* @ClassName: JmsServiceImpl
* @Description: TODO(消息队列服务)
* @author Wei Xing
* @date 2014年10月31日 下午2:44:22
*
*/
@Component
public class JmsServiceImpl implements JmsService {
private static Log logger = LogFactory.getLog(JmsServiceImpl.class);
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
@Qualifier("task_dest")
private Destination destinationVideoTask;
/**
* @Title: sendTextMessage
* @Description: TODO(发送Text消息)
* @author Wei Xing
* @param messageType
* @param message
* @throws
* @date 2014年10月31日 下午5:36:48
*/
@Override
public void sendTextMessage(MessageType messageType, final String message) {
Destination destination = null;
logger.debug("messageType: " + messageType);
logger.debug("message: " + message);
// switch (messageType) {
// case video_submit_topic:
destination = this.destinationVideoTask;
// break;
// case seo_update_topic:
// destination = this.destinationSeoTopic;
// break;
// }
logger.debug("destination: " + destination);
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(message);
}
});
}
/**
* @Title: sendMapMessage
* @Description: TODO(发送Map消息)
* @author Wei Xing
* @param messageType
* @param message
* @throws
* @date 2014年10月31日 下午5:36:48
*/
@Override
public void sendMapMessage(MessageType messageType, final Map<String, Object> message) {
Destination destination = null;
// switch (messageType) {
// case video_submit_topic:
destination = this.destinationVideoTask;
// break;
// case seo_update_topic:
// destination = this.destinationSeoTopic;
// break;
// }
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
MapMessage MapMessage = session.createMapMessage();
for (Map.Entry<String, Object> entry : message.entrySet()) {
MapMessage.setObject((String) entry.getKey(), entry.getValue());
}
return MapMessage;
}
});
}
/**
* @Title: sendBytesMessage
* @Description: TODO(发送Bytes消息)
* @author Wei Xing
* @param messageType
* @param message
* @throws
* @date 2014年10月31日 下午5:36:48
*/
@Override
public void sendBytesMessage(MessageType messageType, final byte[] message) {
Destination destination = null;
// switch (messageType) {
// case video_submit_topic:
destination = this.destinationVideoTask;
// break;
// case seo_update_topic:
// destination = this.destinationSeoTopic;
// break;
// }
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeBytes(message);
return bytesMessage;
}
});
}
/**
* @Title: sendObjectMessage
* @Description: TODO(发送Object消息)
* @author Wei Xing
* @param messageType
* @param message
* @throws
* @date 2014年10月31日 下午5:36:48
*/
@Override
public void sendObjectMessage(MessageType messageType, final Serializable message) {
Destination destination = null;
// switch (messageType) {
// case video_submit_topic:
destination = this.destinationVideoTask;
// break;
// case seo_update_topic:
// destination = this.destinationSeoTopic;
// break;
// }
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createObjectMessage(message);
}
});
}
接收端application-jms.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd"
default-lazy-init="true">
<bean id="jmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.1.100:61616" />
<property name="closeTimeout" value="60000" />
<!--<property name="userName" value="admin" /> -->
<!--<property name="password" value="admin" /> -->
<!--<property name="optimizeAcknowledge" value="true" /> -->
</bean>
</property>
</bean>
<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref bean="jmsConnectionFactory" />
</property>
</bean>
<!--视频通道:发送消息目的地 -->
<bean id="task_dest" name="task_dest" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0">
<value>task_dest</value>
</constructor-arg>
</bean>
<!--queue通道:消息回复目的地 -->
<bean id="defaultResponseQueue" name="defaultResponseQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0">
<value>defaultResponseQueue</value>
</constructor-arg>
</bean>
<!--计划任务消息接收监听器 -->
<bean id="taskMessageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="com.eciyuanjie.jms.listener.TaskMessageListener" />
</constructor-arg>
<property name="defaultListenerMethod" value="receiveMessage"/>
<property name="defaultResponseDestination" ref="defaultResponseQueue"/>
</bean>
<!--视频消息接收监听容器,多线程异步接受消息 -->
<bean id="taskJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="destination" ref="task_dest"/>
<property name="messageListener" ref="taskMessageListener" />
<property name="sessionTransacted" value="false" />
</bean>
</beans>
task_dest为发送端的消息队列,接收端执行后将执行结果反回给defaultResponseQueue,发送端接收后根据参数保存数据库
import java.lang.reflect.Method;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import com.eciyuanjie.data.video.service.VideoService;
import com.eciyuanjie.jms.service.JmsService;
import com.eciyuanjie.utils.ApplicationContextHolder;
/**
* @ClassName: VideoMessageListener
* @Description: TODO(视频消息监听器)
* @author Wei Xing
* @date 2014年11月3日 下午3:04:57
*
*/
public class TaskMessageListener {
@Autowired
private VideoService videoService;
@Autowired
private JmsService jmsService;
/**
* @Title: handleMessage
* @Description: TODO(String)
* @author Wei Xing
* @param message
* @throws
* @date 2014年11月3日 下午3:04:57
*/
public String receiveMessage(String message) {
String []args = message.split("_");
try {
Class targetClass = Class.forName(args[0]);
Object object = ApplicationContextHolder.getApplicationContext().getBean(targetClass);
Method method = targetClass.getMethod(args[1]);
method.invoke(object, new Object[]{});
} catch (BeansException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
<span style="white-space:pre"> System.out.println("--------------------视频任务已执行-------------------"+message);
<span style="white-space:pre"> </span>return args[0]+"_"+ args[1]+"_"+args[2];</span>}}