七、activemq整合springmvc之queue

一、前言

spring代码基于 SSM整合(spring-springmvc-mybatis)之CRUD ;代码地址:(基础版本:https://gitee.com/joy521125/ssm-senior-base.gitmaven版:https://gitee.com/joy521125/ssm-senior.git

代码地址:https://gitee.com/joy521125/ssm-senior.git(activemq 分支)

测试代码:在/emp/list中,设置了一个推送;

jar包:

 

版本:

1 <properties>
2 <org.muses.spring.versin>5.3.18</org.muses.spring.versin>
3 <org.muses.activemq.versin>5.16.5</org.muses.activemq.versin>
4 <org.muses.pagehelper.versin>5.3.0</org.muses.pagehelper.versin>
5 </properties>
View Code

jar包:

 

 1 <!-- activemq所需要的jar包 -->
 2         <dependency>
 3             <groupId>org.apache.activemq</groupId>
 4             <artifactId>activemq-all</artifactId>
 5             <version>${org.muses.activemq.versin}</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>org.apache.xbean</groupId>
 9             <artifactId>xbean-spring</artifactId>
10             <version>4.21</version>
11         </dependency>
12 
13         <!-- https://mvnrepository.com/artifact/org.springframework/spring-jms -->
14         <!-- activeMQ对JMS的支持,整合Spring和ActiveMQ -->
15         <dependency>
16             <groupId>org.springframework</groupId>
17             <artifactId>spring-jms</artifactId>
18             <version>${org.muses.spring.versin}</version>
19         </dependency>
20 
21         <dependency>
22             <groupId>org.apache.activemq</groupId>
23             <artifactId>activemq-pool</artifactId>
24             <version>${org.muses.activemq.versin}</version>
25         </dependency>
View Code

二、activem 队列queue配置

默认是持久化;

 activemq_queue.xml(生产者)配置信息:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 3         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 4     <bean id="mQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
 5         <!-- tcp://自己的服务器地址:端口 -->
 6         <property name="brokerURL" value="tcp://localhost:61616"></property>
 7         <property name="userName" value="admin"></property>
 8         <property name="password" value="admin"></property>
 9         <!-- 强制异步发送大幅提升性能;但意味着无论消息是否已发送,send() 方法都会立即返回,这可能导致消息丢失 -->
10         <property name="useAsyncSend" value="true"></property>
11         <!-- 如果未设置此标志,则不会使用单独的线程为连接中的每个会话分派消息。但是,如果有多个会话,或者会话未处于自动确认或重复 ok 模式,则始终使用单独的线程。 默认情况下,此值设置为 true,并且会话分派异步发生。 -->
12         <property name="alwaysSessionAsync" value="false"></property>
13     </bean>
14 
15     <bean id="connectionFactory" class="org.apache.activemq.jms.pool.PooledConnectionFactory">
16         <property name="connectionFactory" ref="mQConnectionFactory"></property>
17         <property name="maxConnections" value="100"></property>
18     </bean>
19     <!-- 这个是队列目的地,点对点的 -->
20     <bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue">
21         <constructor-arg index="0" value="spring-active-queue"></constructor-arg>
22     </bean>
23 
24     <!-- 发布者配置 实际项目中消费者配置和发布者配置分开 -->
25     <bean id="mQConverter" class="org.springframework.jms.support.converter.SimpleMessageConverter"></bean>
26     <!-- 发布者配置 实际项目中消费者配置和发布者配置分开 -->
27     <bean id="queueTemplate" class="org.springframework.jms.core.JmsTemplate">
28         <property name="connectionFactory" ref="connectionFactory" />
29         <property name="defaultDestination" ref="destinationQueue" />
30         <property name="messageConverter" ref="mQConverter" />
31         <property name="sessionTransacted" value="true" />
32         <!-- 消息持久化配置 这里配置的是持久化 -->
33         <!-- 消息持久化 explicitQosEnabled 必须配置 -->
34         <property name="explicitQosEnabled" value="true"></property>
35         <property name="deliveryPersistent" value="true" /><!-- 非持久化配置为 false -->
36         <property name="deliveryMode" value="2"></property><!-- 非持久化配置为 1 -->
37     </bean>
38     <!-- 发布者配置 实际项目中消费者配置和发布者配置分开 -->
39     <bean class="org.muses.ssm.senior.mgt.core.entity.MessagePublisher">
40         <property name="jmsTemplate" ref="queueTemplate"></property>
41     </bean>
42 
43 </beans>

发布消息MessagePublisher.java:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 3         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 4     <bean id="mQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
 5         <!-- tcp://自己的服务器地址:端口 -->
 6         <property name="brokerURL" value="tcp://localhost:61616"></property>
 7         <property name="userName" value="admin"></property>
 8         <property name="password" value="admin"></property>
 9         <!-- 强制异步发送大幅提升性能;但意味着无论消息是否已发送,send() 方法都会立即返回,这可能导致消息丢失 -->
10         <property name="useAsyncSend" value="true"></property>
11         <!-- 如果未设置此标志,则不会使用单独的线程为连接中的每个会话分派消息。但是,如果有多个会话,或者会话未处于自动确认或重复 ok 模式,则始终使用单独的线程。 默认情况下,此值设置为 true,并且会话分派异步发生。 -->
12         <property name="alwaysSessionAsync" value="false"></property>
13     </bean>
14 
15     <bean id="connectionFactory" class="org.apache.activemq.jms.pool.PooledConnectionFactory">
16         <property name="connectionFactory" ref="mQConnectionFactory"></property>
17         <property name="maxConnections" value="100"></property>
18     </bean>
19     <!-- 这个是队列目的地,点对点的 -->
20     <bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue">
21         <constructor-arg index="0" value="spring-active-queue"></constructor-arg>
22     </bean>
23     <!-- 消费者配置 :监听器  -->
24     <bean id="mqMessageListener" class="org.muses.ssm.senior.mgt.core.utiles.MqMessageListener">
25     </bean>
26     <!-- 消费者配置 实际项目中消费者配置和发布者配置分开 -->
27     <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
28         <property name="connectionFactory" ref="connectionFactory"></property>
29         <property name="destination" ref="destinationQueue"></property>
30           <property name="messageListener" ref="mqMessageListener"></property>
31     </bean>
32 </beans>

 

web.xml中添加 activemq_queue.xml配置:

1     <context-param>
2         <param-name>contextConfigLocation</param-name>
3         <param-value>classpath:spring.xml,classpath:activemq_queue.xml</param-value>
4     </context-param>

完整web.xml:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 4     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
 5     version="4.0">
 6     <filter>
 7         <filter-name>CharacterEncodingFilter</filter-name>
 8         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
 9         <init-param>
10             <param-name>encoding</param-name>
11             <param-value>utf-8</param-value>
12         </init-param>
13     </filter>
14     <filter-mapping>
15         <filter-name>CharacterEncodingFilter</filter-name>
16         <url-pattern>/*</url-pattern>
17     </filter-mapping>
18     <context-param>
19         <param-name>contextConfigLocation</param-name>
20         <param-value>classpath:spring.xml,classpath:activemq_queue.xml</param-value>
21     </context-param>
22     <listener>
23         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
24     </listener>
25     <servlet>
26         <servlet-name>springDispatcherServlet</servlet-name>
27         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
28         <init-param>
29             <param-name>contextConfigLocation</param-name>
30             <param-value>classpath:springmvc.xml</param-value>
31         </init-param>
32         <load-on-startup>1</load-on-startup>
33     </servlet>
34 
35     <servlet-mapping>
36         <servlet-name>springDispatcherServlet</servlet-name>
37         <url-pattern>/</url-pattern>
38     </servlet-mapping>
39      <!-- 配置HiddenHttpMethodFilter :可以把post请求转为delete or put请求 -->
40 
41     <filter>
42         <filter-name>HiddenHttpMethodFilter</filter-name>
43         <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
44     </filter>
45     <filter-mapping>
46         <filter-name>HiddenHttpMethodFilter</filter-name>
47         <url-pattern>/*</url-pattern>
48     </filter-mapping>
49 </web-app>
View Code

MqMessageListener:

 1 package org.muses.ssm.senior.mgt.core.utiles;
 2 
 3 import javax.jms.Message;
 4 import javax.jms.MessageListener;
 5 import javax.jms.TextMessage;
 6 
 7 public class MqMessageListener implements MessageListener {
 8 
 9     @Override
10     public void onMessage(Message message) {
11         if (null != message && message instanceof TextMessage) {
12             TextMessage textMessage = (TextMessage) message;
13             System.out.println("textMessage:" + textMessage);
14         }
15     }
16 
17 }
View Code

 推送方法MessagePublisher :

 1 package org.muses.ssm.senior.mgt.core.entity;
 2 
 3 import org.springframework.jms.core.JmsTemplate;
 4 
 5 public class MessagePublisher {
 6 
 7     private static JmsTemplate jmsTemplate;
 8 
 9     public static JmsTemplate getJmsTemplate() {
10         return jmsTemplate;
11     }
12 
13     public static void setJmsTemplate(JmsTemplate jmsTemplate) {
14         MessagePublisher.jmsTemplate = jmsTemplate;
15     }
16 
17     public static void sendMessage(Object message) {
18         jmsTemplate.convertAndSend(message);
19     }
20 
21 }
View Code

 

三、事务配置

在Spring+JMS的设计里面,通过sessionTransacted=true可以满足jms的事务,但是这个事务说的是在消费者端,也就是消费不成功会消息会回滚再次被消费。

事务配置

只需要更改activemq_queue.xml 配置信息;增加属性sessionTransacted 属性值设置为true;表示jms的事务由spring托管,但是发送消息中如果又异常,依然会推送。需要在消费者端配置事务,才能达到回滚的效果。如果消费者端有异常,该条消息被重复发送多次(默认重发6次,redeliveryCounter=6),之后将会被移入到死信队列(非持久消息不回放入死性队列),之后broker不会再将该消息发送给消费者。

即:

 1 <!-- 发布者配置 实际项目中消费者配置和发布者配置分开 -->
 2     <bean id="queueTemplate" class="org.springframework.jms.core.JmsTemplate">
 3         <property name="connectionFactory" ref="connectionFactory" />
 4         <property name="defaultDestination" ref="destinationQueue" />
 5         <property name="messageConverter" ref="mQConverter" />
 6         <!-- 开启事务配置 -->
 7         <property name="sessionTransacted" value="true" />
 8         <!-- 消息持久化配置 这里配置的是持久化 -->
 9         <!-- 消息持久化 explicitQosEnabled 必须配置 -->
10         <property name="explicitQosEnabled" value="true"></property>
11         <property name="deliveryPersistent" value="true" /><!-- 非持久化配置为 false -->
12         <property name="deliveryMode" value="2"></property><!-- 非持久化配置为 1 -->
13     </bean>

官方文档地址:https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#jms

1 @Override
2     public void onMessage(Message message) {
3         if (null != message && message instanceof TextMessage) {
4             TextMessage textMessage = (TextMessage) message;
5             System.out.println("textMessage:" + textMessage);
6             int a = 1 / 0;
7         }
8     }
1  <!-- 消费者配置 实际项目中消费者配置和发布者配置分开 -->
2     <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
3         <property name="connectionFactory" ref="connectionFactory"></property>
4         <property name="destination" ref="destinationQueue"></property>
5           <property name="messageListener" ref="mqMessageListener"></property>
6           <property name="sessionTransacted" value="true" />
7     </bean>

 

那么效果就是:

持久化队列

非持久化队列

 

四、签收

  1. AUTO_ACKNOWLEDGE = 1 :自动确认
  2. CLIENT_ACKNOWLEDGE = 2:客户端手动确认
  3. DUPS_OK_ACKNOWLEDGE = 3: 自动批量确认
  4. SESSION_TRANSACTED = 0:事务提交并确认
  5. INDIVIDUAL_ACKNOWLEDGE = 4:单条消息确认   但是在activemq补充了一个自定义的ACK模式:

设置签收方式,必须关闭事务,否则签收方式的配置无效;

1     <!-- 消费者配置 实际项目中消费者配置和发布者配置分开 -->
2     <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
3         <property name="connectionFactory" ref="connectionFactory"></property>
4         <property name="destination" ref="destinationQueue"></property>
5         <property name="messageListener" ref="mqMessageListener"></property>
6         <property name="sessionTransacted" value="false"></property><!-- 设置签收方式,必须关闭事务 -->
7         <property name="sessionAcknowledgeMode" value="4"></property><!-- 设置手动签收 -->
8     </bean>

消息监听,设置手动签收:

 1  @Override
 2     public void onMessage(Message message) {
 3         if (null != message && message instanceof TextMessage) {
 4             TextMessage textMessage = (TextMessage) message;
 5             System.out.println("textMessage:" + textMessage);
 6             try {
 7                 message.acknowledge();// 手动签收
 8             } catch (JMSException e) {
 9                 // TODO Auto-generated catch block
10                 e.printStackTrace();
11             }
12         }
13     }

 

 如果消息监听没有设置了签收:

 

sessionAcknowledgeMode 设置为2时,不管客户端设置不设置签收都会签收,原因如下:

 

参考地址:https://blog.csdn.net/weixin_45150104/article/details/123884015

posted @ 2022-09-28 22:40  啄木鸟伍迪  阅读(105)  评论(0)    收藏  举报
//火箭 GenerateContentList();