前言
上篇讲了activeMQ之Queue(队列)基础知识点,在此基础上加入websocket,消息的持久化、消费者手动签收机制、消息重发机制。
springboot整合activeMQ系列之Queue(一)
在系列一的基础上对消费者工程改造
pom文件增加了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
消费者目录
配置文件
配置文件有websocket的配置和activeMQ队列的持久化、签收、重发机制的相关设计
package com.example.bootcustomer.config;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.RedeliveryPolicy;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import javax.jms.DeliveryMode;
import javax.jms.Queue;
import javax.jms.Session;
/**
* @Desc 消费者和生产者的配置类差不多,生产者不用配置websocket去掉就好,其他都是一样的
*/
@Configuration
@EnableJms
public class BeanConfig {
@Value("${myQueue}")
private String myQueue;
/**
* websocket配置Bean
*
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
/**
* 定义存放消息的队列
* @return
*/
@Bean
public Queue queue() {
return new ActiveMQQueue(myQueue);
}
@Bean
public RedeliveryPolicy redeliveryPolicy() {
RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
//是否在每次尝试重新发送失败后,增长这个等待时间
redeliveryPolicy.setUseExponentialBackOff(true);
//重发次数,默认为6次 这里设置为10次
redeliveryPolicy.setMaximumRedeliveries(10);
//重发时间间隔,默认为1秒
redeliveryPolicy.setInitialRedeliveryDelay(1);
//第一次失败后重新发送之前等待500毫秒,第二次失败再等待500 * 2毫秒,这里的2就是value
redeliveryPolicy.setBackOffMultiplier(2);
//是否避免消息碰撞
redeliveryPolicy.setUseCollisionAvoidance(false);
//设置重发最大拖延时间10s 只有UseExponentialBackOff(true)为true时才表示没有拖延时间
redeliveryPolicy.setMaximumRedeliveryDelay(10000L);
return redeliveryPolicy;
}
@Bean
public ActiveMQConnectionFactory activeMQConnectionFactory(RedeliveryPolicy redeliveryPolicy) {
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory();
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
return activeMQConnectionFactory;
}
@Bean
public JmsTemplate jmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory, Queue queue) {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);//进行持久化配置 NON_PERSISTENT - 表示非持久化,PERSISTENT - 表示持久化
jmsTemplate.setConnectionFactory(activeMQConnectionFactory);
jmsTemplate.setDefaultDestination(queue); //此处可不设置默认,在发送消息时也可设置队列
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);//客户端签收模式
// CLIENT_ACKNOWLEDGE -- 客户确认 DUPS_OK_ACKNOWLEDGE -- 自动批量确认
// SESSION_TRANSACTED -- 事务提交并确认 AUTO_ACKNOWLEDGE -- 自动签收
return jmsTemplate;
}
/**
* 定义一个消息监听器连接工厂,这里定义的是点对点模式的监听器连接工厂
*
* @param activeMQConnectionFactory
* @return
*/
@Bean(name = "jmsQueueListener")
public DefaultJmsListenerContainerFactory jmsQueueListenerContainerFactory(ActiveMQConnectionFactory activeMQConnectionFactory) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(activeMQConnectionFactory);
//设置连接数
factory.setConcurrency("1-10");
//重连间隔时间
factory.setRecoveryInterval(10000L);
factory.setSessionAcknowledgeMode(4);
return factory;
}
}
Queue_Customer类
package com.example.bootcustomer.customer;
import lombok.Data;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.TextMessage;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.Session;
/**
* @Desc 消费者类
*/
@ServerEndpoint("/websocket")
@Component
@Data
public class Queue_Customer {
/**
* 每个客户端都会有相应的session,服务端可以发送相关消息
*/
private Session session;
/**
* J.U.C包下线程安全的类,主要用来存放每个客户端对应的webSocket连接
*/
private static CopyOnWriteArraySet<Queue_Customer> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
this.session = session;
copyOnWriteArraySet.add(this);
}
@OnClose
public void onClose() {
copyOnWriteArraySet.remove(this);
}
@OnMessage
public void onMessage(String message) {
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
@JmsListener(destination = "${myQueue}", containerFactory = "jmsQueueListener") //监听
public void receive(TextMessage textMessage, javax.jms.Session session) throws JMSException {
//遍历客户端
for (Queue_Customer webSocket : copyOnWriteArraySet) {
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendText(textMessage.getText());
textMessage.acknowledge();// 使用手动签收模式,需要手动的调用,如果不在catch中调用session.recover()消息只会在重启服务后重发
System.out.println("websocket-1号消费者" + textMessage.getText());
} catch (Exception e) {
session.recover();// 此不可省略 重发信息使用
}
}
}
}
启动类和系列一致springboot整合activeMQ系列之Queue(一),就不赘述了!
生产者工程
生产者工程需要把之前的配置文件改成和消费者一样,去掉websocket就可以,pom文件不用改。
Queue_Produce 类
package com.example.provider.produce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.jms.Queue;
import java.util.UUID;
/**
* @Desc 生产者
*/
@Component
public class Queue_Produce {
// @Autowired
// private JmsMessagingTemplate jmsMessagingTemplate; //系列一
@Autowired
private Queue queue;
@Autowired
private JmsTemplate jmsTemplate;
/**
* 间隔10秒钟定投
*/
@Scheduled(fixedDelay = 10000)
public void produceMsgScheduled() {
jmsTemplate.convertAndSend(queue, "$$$$$$$:" + UUID.randomUUID().toString().substring(0, 7));
System.out.println("produceMsgScheduled send ok");
}
}
运行结果图:
生产者:
消费者:
activeMQ图: