ActiveMQ与Spring的集成
首先将ActiveMQ如下的jar包导入项目中。
配置activemq的spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
<!--(嵌入配置)activeMq消息容器-->
<amq:broker useJmx="true" persistent="true" >
<amq:managementContext>
<amq:managementContext createConnector="false"/>
</amq:managementContext>
<amq:persistenceAdapter>
<amq:kahaDB directory="${jmsDir}" >
</amq:kahaDB>
</amq:persistenceAdapter>
<amq:transportConnectors>
<amq:transportConnector uri="tcp://${jms.ip}:${jms.port}" />
</amq:transportConnectors>
</amq:broker>
<!-- wireFormat.maxInactivityDuration=0& -->
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://${jms.ip}?jms.useAsyncSend=true" />
</bean>
<bean id="simpleJmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory"/>
<property name="sessionCacheSize" value="100" />
<property name="cacheConsumers" value="true"></property>
<property name="exceptionListener" ref="jmsExceptionListener"/>
</bean>
<bean id="jmsExceptionListener" class="com.ibms.core.jms.JmsExceptionListener"></bean>
<!-- Message 转换器 -->
<bean id="activeMqMessageConverter" class="com.ibms.core.jms.ActiveMqMessageConverter"/>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="simpleJmsConnectionFactory" />
<property name="defaultDestinationName" value="messageQueue"/>
</bean>
<!-- 消息对象队列 -->
<amq:queue id="messageQueue" name="messageQueue" physicalName="messageQueue" />
<!-- 消息生产者 -->
<bean id="messageProducer" class="com.ibms.core.jms.MessageProducer"/>
<!--
消息消费者
map配置的是队列中消息处理类。
键:队列中消息类 对应的类 全路径 如: com.ibms.core.model.MailModel
值:消息处理类,需要实现接口类IJmsHandler 。如:com.ibms.oa.service.jms.impl.MailHandler
用户也可以配置自己的处理方式,配置到这里。
-->
<bean name="messageConsumer" class="com.ibms.core.jms.MessageConsumer">
<property name="handlers">
<map>
<entry key="com.ibms.oa.service.jms.MessageModel">
<bean class="com.ibms.oa.service.jms.MessageHandler"></bean>
</entry>
</map>
</property>
</bean>
<!--
map配置的是队列中消息处理类。
键:1,2,3
值:消息处理类,需要实现接口类IMessageHandler 。
用户也可以配置自己的处理方式,配置到这里。
每增加一种消息方式的时候,需要增加对应的处理器(如下,如mailMessageHandler实现IMessageHandler 接口)-->
<bean id="mailMessageHandler" class="com.ibms.oa.service.jms.MailMessageHandler"></bean>
<bean id="innerMessageHandler" class="com.ibms.oa.service.jms.InnerMessageHandler"></bean>
<bean id="messageHandlerContainer " class="com.ibms.oa.service.jms.MessageHandlerContainer">
<property name="handlersMap" ref="handlersMap"/>
</bean>
<bean id="handlersMap" class="java.util.LinkedHashMap">
<constructor-arg>
<map>
<entry key="1" value-ref="mailMessageHandler" />
<entry key="3" value-ref="innerMessageHandler" />
</map>
</constructor-arg>
</bean>
<!--消息监听容器 -->
<bean id="messageListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="simpleJmsConnectionFactory" />
<property name="destination" ref="messageQueue" />
<property name="messageListener" ref="messageMsgListener" />
</bean>
<!-- 邮件消息消费监听器 -->
<bean id="messageMsgListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<ref bean="messageConsumer"/>
</constructor-arg>
<property name="messageConverter" ref="activeMqMessageConverter" />
<property name="defaultListenerMethod" value="sendMessage" />
</bean>
<bean id="messageEngine" class="com.ibms.core.engine.MessageEngine">
<property name="mailSender" ref="mailSender"/>
<property name="fromUser" value="${mail.from}"/>
</bean>
</beans>
然后依次实现消息的转换器ActiveMqMessageConverter
public class ActiveMqMessageConverter implements MessageConverter {
/**
* 转换发送消息。
*/
@Override
public Message toMessage(Object object, Session session)
throws JMSException {
}
/**
* 转换接收消息。
*/
@Override
public Object fromMessage(Message msg) throws JMSException {
}
}
消息的生产者MessageProducer
public class MessageProducer
{
private static final Log logger=LogFactory.getLog(MessageProducer.class);
@Resource(name="messageQueue")
private Queue messageQueue;
@Resource
private JmsTemplate jmsTemplate;
public void send(Object model)
{
logger.debug("procduce the message");
//产生邮件\短信\消息发送的消息,加到消息队列中去
jmsTemplate.convertAndSend(messageQueue, model);
}
}
消息的消费者MessageConsumer(可扩展)
/**
* 从消息队列中读取对象,并且进行消息发送。
*
* @author zxh
*
*/
public class MessageConsumer {
/**
* 处理消息
*/
private Map<String, IJmsHandler> handlers = new HashMap<String, IJmsHandler>();
protected Logger logger = LoggerFactory.getLogger(MessageConsumer.class);
public void setHandlers(Map<String, IJmsHandler> handlers) {
this.handlers = handlers;
}
/**
* 发送消息
*
* @param model
* 发送的对象
* @throws Exception
*/
public void sendMessage(Object model) throws Exception {
if (BeanUtils.isNotEmpty(handlers) && BeanUtils.isNotEmpty(model)) {
IJmsHandler jmsHandler = handlers.get(model.getClass().getName());
if(jmsHandler!=null){
jmsHandler.handMessage(model);
}
else{
logger.info(model.toString());
}
} else {
throw new Exception("Object:[" + model + "] is not entity Object ");
}
}
}
ActiveMQ应用场景
消息队列是分布式系统中重要的组件,可以解决异步处理,应用接耦,流量削峰,日志处理,消息通讯
异步处理:用户注册后需要发送注册邮件和注册短信,就可以放入消息队列中,不用管了,它会处理直到处理成功
应用解耦:用户下单并支付成功后,就会有如下流程:1,成本核算2,库存系统减少3,财务通知,4商家通知等等是在同一事务中,如果这4步任何一部出现错误或抛异常,这样事务就会回滚,钱又退回用户账号,这是绝对不能出现的情况,我们可以把这4个流程放在一个消息队列中,相互互不影响,只要放入消息队列,就不用管了,以下4个流程会订阅取得消息
流量削峰:一般出现在秒杀或者团抢活动中,放到消息队列中,1.可以控制活动的人数(如果消息队列长度超过最大数量就会直接抛弃或者跳转到错误页面),2,可以缓解短时间高流量压垮应用(起到缓冲的作用,然后再处理秒杀业务)。
日志处理:日志采集客户端把日志写入kafka消息队列,然后日志处理应用去订阅
消息通讯:聊天室功能