基于Spring的异步系统实现方案
一般的实现方案
发送异步消息所使用的工具类:
1 import java.util.Date; 2 import javax.jms.Destination; 3 import javax.jms.JMSException; 4 import javax.jms.Message; 5 import javax.jms.Session; 6 import org.apache.activemq.command.ActiveMQMapMessage; 7 import org.apache.activemq.command.ActiveMQObjectMessage; 8 import org.apache.shiro.SecurityUtils; 9 import org.slf4j.Logger; 10 import org.slf4j.LoggerFactory; 11 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.beans.factory.annotation.Qualifier; 13 import org.springframework.jms.core.JmsTemplate; 14 import org.springframework.jms.core.MessageCreator; 15 import org.springframework.stereotype.Component; 16 @Component 17 public class AsyncUtils { 18 private static Logger log = LoggerFactory.getLogger(AsyncUtils.class); 19 private static JmsTemplate jmsTemplate; 20 private static Destination sendMailDestination; 21 private static Destination LoginLogDestination; 22 private static Destination normalLogDestination; 23 private static Destination pushNotificationDestination; 24 public static void log(String type,String operate){ 25 if(!SystemConfigFromDB.getBoolean(SystemConfigFromDB.NEED_NORMAL_LOG)){ 26 return; 27 } 28 try{ 29 User user = (User) SecurityUtils.getSubject().getSession().getAttribute("loginUser"); 30 if(user==null){ 31 return; 32 } 33 OperateLog log = new OperateLog(user.getId(), user.getName(), operate,type, user.getLastLoginIp()); 34 final ActiveMQObjectMessage message = new ActiveMQObjectMessage(); 35 message.setObject(log); 36 //AsycWorkFactory.sendMessage(message, AsycWork.NORMAL_LOG); 37 jmsTemplate.send(normalLogDestination, new MessageCreator() { 38 @Override 39 public Message createMessage(Session session) throws JMSException { 40 return message; 41 } 42 }); 43 }catch (Exception e) { 44 log.error("日志记录出错!", e); 45 } 46 } 47 public static void sendMail(String address,String title,String content){ 48 if(!SystemConfigFromDB.getBoolean(SystemConfigFromDB.NEED_SEND_MAIL)){ 49 return; 50 } 51 try{ 52 final ActiveMQMapMessage message = new ActiveMQMapMessage(); 53 message.setString("address", address); 54 message.setString("title", title); 55 message.setString("content", content); 56 //AsycWorkFactory.sendMessage(message, AsycWork.EMAIL); 57 jmsTemplate.send(sendMailDestination, new MessageCreator() { 58 @Override 59 public Message createMessage(Session session) throws JMSException { 60 return message; 61 } 62 }); 63 }catch (Exception e) { 64 log.error("邮件发送出错!",e); 65 } 66 } 67 public static void loginLog(String uid,String ip,Date date){ 68 if(!SystemConfigFromDB.getBoolean(SystemConfigFromDB.NEED_LOG_CLIENTUSER_LOGINLOG)){ 69 return; 70 } 71 try{ 72 final ActiveMQMapMessage message = new ActiveMQMapMessage(); 73 message.setString("uid", uid); 74 message.setString("ip", ip); 75 message.setString("date", DateUtils.formatDateTime(date, "yyyy-MM-dd HH:mm:ss")); 76 //AsycWorkFactory.sendMessage(message, AsycWork.LOGIN_LOG); 77 jmsTemplate.send(LoginLogDestination, new MessageCreator() { 78 @Override 79 public Message createMessage(Session session) throws JMSException { 80 return message; 81 } 82 }); 83 }catch (Exception e) { 84 log.error("邮件发送出错!",e); 85 } 86 } 87 public static void pushNotification(String id,String content){ 88 if(!SystemConfigFromDB.getBoolean(SystemConfigFromDB.NEED_LOG_CLIENTUSER_LOGINLOG)){ 89 return; 90 } 91 try{ 92 final ActiveMQMapMessage message = new ActiveMQMapMessage(); 93 message.setString("id", id); 94 message.setString("content", content); 95 jmsTemplate.send(normalLogDestination, new MessageCreator() { 96 @Override 97 public Message createMessage(Session session) throws JMSException { 98 return message; 99 } 100 }); 101 }catch (Exception e) { 102 log.error("消息推送出错!",e); 103 } 104 } 105 @Autowired 106 public void setJmsTemplate(JmsTemplate jmsTemplate) { 107 AsyncUtils.jmsTemplate = jmsTemplate; 108 } 109 @Autowired 110 @Qualifier("sendMailDestination") 111 public void setSendMailDestination(Destination sendMailDestination) { 112 AsyncUtils.sendMailDestination = sendMailDestination; 113 } 114 @Autowired 115 @Qualifier("LoginLogDestination") 116 public void setLoginLogDestination(Destination loginLogDestination) { 117 LoginLogDestination = loginLogDestination; 118 } 119 @Autowired 120 @Qualifier("normalLogDestination") 121 public void setNormalLogDestination(Destination normalLogDestination) { 122 AsyncUtils.normalLogDestination = normalLogDestination; 123 } 124 @Autowired 125 @Qualifier("pushNotificationDestination") 126 public void setPushNotificationDestination( 127 Destination pushNotificationDestination) { 128 AsyncUtils.pushNotificationDestination = pushNotificationDestination; 129 } 130 }
监听异步消息的监听器类(可以给每个类型的消息设定不同的监听器):
1 @Component 2 public class EmailListener implements MessageListener { 3 private static Logger log = LoggerFactory.getLogger(EmailListener.class); 4 @Override 5 public void onMessage(Message message) { 6 ActiveMQMapMessage msg = (ActiveMQMapMessage) message; 7 try { 8 String address = msg.getString("address"); 9 String title = msg.getString("title"); 10 String content = msg.getString("content"); 11 Constants.sendMail(address, title, content); 12 } catch (Exception e) { 13 log.error("异步邮件发送异常", e); 14 } 15 } 16 }
使用方式:
//异步发送邮件 AsyncUtils.sendMail("邮件地址","主题","内容"); //即可
Spring配置文件:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:core="http://activemq.apache.org/schema/core" 6 xmlns:jms="http://www.springframework.org/schema/jms" 7 xmlns:context="http://www.springframework.org/schema/context" 8 xmlns:lang="http://www.springframework.org/schema/lang" 9 xmlns:util="http://www.springframework.org/schema/util" 10 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 11 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 12 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 13 http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.9.0.xsd 14 http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd 15 http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd 16 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"> 17 <!-- ActiveMQ 异步任务 --> 18 <context:annotation-config/> 19 <!-- 存放异步操作相关需要Spring管理的类的包 --> 20 <context:component-scan base-package="com.xxx.core.async" /> 21 <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 --> 22 <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 23 <property name="brokerURL" value="tcp://192.168.7.21:61616" /> 24 </bean> 25 <!-- 带连接池的JMS链接工厂 --> 26 <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"> 27 <property name="connectionFactory" ref="targetConnectionFactory" /> 28 <property name="maxConnections" value="10" /> 29 </bean> 30 <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory --> 31 <bean id="connectionFactory" 32 class="org.springframework.jms.connection.SingleConnectionFactory"> 33 <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory --> 34 <property name="targetConnectionFactory" ref="pooledConnectionFactory" /> 35 </bean> 36 <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 --> 37 <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> 38 <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 --> 39 <property name="connectionFactory" ref="connectionFactory" /> 40 </bean> 41 <bean id="sendMailDestination" class="org.apache.activemq.command.ActiveMQQueue"> 42 <constructor-arg value="SendEmail"/> 43 </bean> 44 <bean id="LoginLogDestination" class="org.apache.activemq.command.ActiveMQQueue"> 45 <constructor-arg value="LoginLog"/> 46 </bean> 47 <bean id="normalLogDestination" class="org.apache.activemq.command.ActiveMQQueue"> 48 <constructor-arg value="NormalLog"/> 49 </bean> 50 <bean id="pushNotificationDestination" class="org.apache.activemq.command.ActiveMQQueue"> 51 <constructor-arg value="Notification"/> 52 </bean> 53 <!-- 消息监听容器 --> 54 <bean id="jmsEmailContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 55 <property name="connectionFactory" ref="connectionFactory" /> 56 <property name="destination" ref="sendMailDestination" /> 57 <property name="messageListener" ref="emailListener" /> <!-- 设置监听对象 --> 58 </bean> 59 <bean id="jmsLoginLogContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 60 <property name="connectionFactory" ref="connectionFactory" /> 61 <property name="destination" ref="LoginLogDestination" /> 62 <property name="messageListener" ref="loginLogListener" /> <!-- 设置监听对象 --> 63 </bean> 64 <bean id="jmsNormalLogContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 65 <property name="connectionFactory" ref="connectionFactory" /> 66 <property name="destination" ref="normalLogDestination" /> 67 <property name="messageListener" ref="normalLogListener" /> <!-- 设置监听对象 --> 68 </bean> 69 <bean id="jmsNotificationContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 70 <property name="connectionFactory" ref="connectionFactory" /> 71 <property name="destination" ref="pushNotificationDestination" /> 72 <property name="messageListener" ref="pushNotificationListener" /> <!-- 设置监听对象 --> 73 </bean> 74 </beans>