前言
上篇講了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圖: