springboot整合activeMQ -- Queue模式(篇二)

前言

上篇講了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圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章