通過mq中間件完成異步發送郵件實現思路:
【1】 本地項目-->【2】activeMQ--->【3】消費者(jms)
說明:
【1】本地項目,創建郵件模板,通過JmsTemple發送給MQ,進入消息隊列,是不折不扣的生產者。由於本文討論的是是運用spring整合activeMQ,需要將jms提供鏈接的ConnectionFactory交給spring容器管理。
【2】 mq本身嵌套一個jetty服務器,可存儲生產者端發送的消息隊列。
【3】 消費者端,mq通過messageListener監聽器監聽並得到消息隊列中的消息並對消息做處理。實現異步發送。
總體代碼實現:
A.maven引入相關jar
<!-- -spring frame start --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> <!-- -spring frame end -->
<!-- java email --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> </dependency>
<!-- activiti mq 的jar包 start--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-all</artifactId> <version>${activemq.version}</version> </dependency> <!--activiti mq end --> |
B、jms鏈接交給spring管理
<!-- 配置JMS鏈接模版 --> <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616" /> <property name="clientID" value="api2_producer" /> </bean> |
C、生產者配置
<!--生產者 start --> <!-- 配置JMS模版 --> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="defaultDestination" ref="defaultDestination" /> <property name="connectionFactory" ref="connectionFactory" /> <property name="pubSubDomain" value="false" /> <!-- deliveryMode, priority, timeToLive 的開關,要生效,必須配置爲true,默認false --> <property name="explicitQosEnabled" value="true" /> <!-- 發送模式 DeliveryMode.NON_PERSISTENT=1:非持久 ; DeliveryMode.PERSISTENT=2:持久 --> <property name="deliveryMode" value="1" /> <!-- 消息應答方式 Session.AUTO_ACKNOWLEDGE 消息自動簽收 Session.CLIENT_ACKNOWLEDGE 客戶端調用acknowledge方法手動簽收 Session.DUPS_OK_ACKNOWLEDGE 不必必須簽收,消息可能會重複發送 --> <property name="sessionAcknowledgeMode" value="2" /> </bean>
<!-- 發送消息的目的地(一個隊列) --> <bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue"> <!-- 設置消息隊列的名字 --> <constructor-arg index="0" value="defaultJmsQueue" /> </bean> |
D、創建生產者消息轉換器
publicclass InnerMessageConverter implements MessageConverter{ @Override public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException { MapMessage message = session.createMapMessage();
@SuppressWarnings("all") Map<String, Object> map = (Map) object;
message.setObject("title", map.get("title")); message.setObject("content", map.get("content")); message.setObject("to", map.get("to")); message.setObject("cc", map.get("cc")); message.setObject("type", map.get("type"));
returnmessage; }
@Override public Object fromMessage(Message message) throws JMSException, MessageConversionException { returnmessage; } } |
E、消費者配置,監聽器配置:
<!-- 配置JMS鏈接模版 --> <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"> <property name="brokerURL" value="${brokerURL}" /> <property name="clientID" value="${clientId}" /> </bean>
<!-- 發送消息的目的地(一個隊列) --> <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue"> <!-- 設置消息隊列的名字 --> <constructor-arg index="0" value="defaultJmsQueue" /> </bean>
<!-- 配置JMS模版 --> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="defaultDestination" ref="destination" /> <property name="connectionFactory" ref="connectionFactory" /> <property name="pubSubDomain" value="false" /> <!-- deliveryMode, priority, timeToLive 的開關,要生效,必須配置爲true,默認false --> <property name="explicitQosEnabled" value="true" /> <!-- 發送模式 DeliveryMode.NON_PERSISTENT=1:非持久 ; DeliveryMode.PERSISTENT=2:持久 --> <property name="deliveryMode" value="1" /> <!-- 消息應答方式 Session.AUTO_ACKNOWLEDGE 消息自動簽收 Session.CLIENT_ACKNOWLEDGE 客戶端調用acknowledge方法手動簽收 Session.DUPS_OK_ACKNOWLEDGE 不必必須簽收,消息可能會重複發送 --> <property name="sessionAcknowledgeMode" value="2" /> </bean>
<!--給消息獲取類加個監聽讓他能自動獲取消息 --> <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="destination" ref="destination" /> <property name="messageListener" ref="messageReceiver" /> <!-- 該屬性值默認爲false,這樣JMS在進行消息監聽的時候就會進行事務控制,當在接收消息時監聽器執行失敗時JMS就會對接收到的消息進行回滾, --> <property name="sessionTransacted" value="false" /> </bean> |
F、消費者實現MessageListener接口
publicvoid processMessage(MapMessage message) throws Exception { //根據消息類型來判斷使用具體的發送消息類 IMessageSender sender = this.factory.getMessageSender(message.getString(MessageConstant.MessageType)); if (null == sender) { thrownew RuntimeException("Not Support"); } try { sender.sendMessage(message); } catch (Exception ex) { log.error(ex); thrownew RuntimeException("Not Support"); } } |