《SpringBoot2.0 實戰》系列-整合Activemq實現點對點、發佈訂閱模式共存、消息持久化、重試等

簡介

Apache ActiveMQApache軟件基金會所研發的開放源代碼消息中間件;由於ActiveMQ是一個純Java程序,因此只需要操作系統支持Java虛擬機,ActiveMQ便可執行。

作用

  • 應用解耦
  • 異步通信
  • 流量削峯
  • 消息通訊

安裝 

提供docker的安裝方式,其他方式網上也都有很多

https://blog.csdn.net/HXNLYW/article/details/88950291

與springboot整合 

jar依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!--如果參數配置pool爲true的話,需要引入下列依賴包-->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-pool</artifactId>
</dependency>

配置文件

spring: 
  # activemq
  activemq:
    broker-url: tcp://xxx:61616
    user: admin
    password: admin
    pool:
      enabled: true
      max-connections: 100
    packages:
      #注意 對象傳輸需開啓包白名單 否則會報錯- -
      trust-all: true 
    in-memory: true
    # 自定義queue名稱
    queue-name: gourd-queue
    # 自定義topic名稱
    topic-name: gourd-topic
  jms:
    # 開啓發布訂閱模式
    pub-sub-domain: true

配置類

配置類加上@EnableJms註解,註冊重試、持久化配置bean

/**
 * active消息隊列配置
 * @author gour.hu
 */
@Configuration
@EnableJms
public class ActiveMqConfig {

    /**
     * 定義存放消息的隊列
     * @return
     */
    @Bean
    public Queue queue(@Value("${spring.activemq.queue-name}")String queueName) {
        return new ActiveMQQueue(queueName);
    }

    /**
     * 發佈訂閱模式
     * @return
     */
    @Bean
    public Topic topic(@Value("${spring.activemq.topic-name}")String topicName) {
        return new ActiveMQTopic(topicName);
    }

    @Bean
    public RedeliveryPolicy redeliveryPolicy(){
        RedeliveryPolicy  redeliveryPolicy=   new RedeliveryPolicy();
        // 啓用指數倍數遞增的方式增加延遲時間。
        redeliveryPolicy.setUseExponentialBackOff(true);
        // 重連時間間隔遞增倍數,只有值大於1和啓用useExponentialBackOff參數時才生效。默認5
        redeliveryPolicy.setBackOffMultiplier(2);
        // 最大重傳次數,達到最大重連次數後拋出異常。爲-1時不限制次數,爲0時表示不進行重傳。默認6
        redeliveryPolicy.setMaximumRedeliveries(6);
        // 重發時間間隔,默認爲1秒
        redeliveryPolicy.setInitialRedeliveryDelay(5000L);
        // 啓用防止衝突功能,因爲消息接收時是可以使用多線程併發處理的,應該是爲了重發的安全性,避開所有併發線程都在同一個時間點進行消息接收處理。
        redeliveryPolicy.setUseCollisionAvoidance(true);
        // 設置重發最大拖延時間-1 表示沒有拖延只有UseExponentialBackOff(true)爲true時生效
        redeliveryPolicy.setMaximumRedeliveryDelay(-1);

        return redeliveryPolicy;
    }


    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory (@Value("${spring.activemq.broker-url}")String url,
          @Value("${spring.activemq.user}")String user, @Value("${spring.activemq.password}")String password,
                                                                RedeliveryPolicy redeliveryPolicy){
        ActiveMQConnectionFactory activeMQConnectionFactory =
                new ActiveMQConnectionFactory(user,password,url);
        activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
        return activeMQConnectionFactory;
    }

    @Bean
    public JmsTemplate getJmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory,
        MessageConverter jacksonJmsMessageConverter,@Value("${spring.jms.pub-sub-domain}")Boolean subAdmin){
        //使用CachingConnectionFactory可以提高部分性能。
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
        cachingConnectionFactory.setSessionCacheSize(100);
        cachingConnectionFactory.setTargetConnectionFactory(activeMQConnectionFactory);
        JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
        //設置deliveryMode(持久化)
        jmsTemplate.setExplicitQosEnabled(true);
        // 設置消息是否持久化
        jmsTemplate.setDeliveryPersistent(true);
        // 設置消息轉換器
        jmsTemplate.setMessageConverter(jacksonJmsMessageConverter);
        // 設置消息是否以事務
        jmsTemplate.setSessionTransacted(true);
        jmsTemplate.setPubSubDomain(subAdmin);
        return jmsTemplate;
    }

    /**
     * topic模式的ListenerContainer
     *
     * @param activeMQConnectionFactory
     * @return
     */
    @Bean("jmsListenerContainerTopic")
    public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ActiveMQConnectionFactory activeMQConnectionFactory,
           DefaultJmsListenerContainerFactoryConfigurer configurer,@Value("${spring.application.name}")String applicationName) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, activeMQConnectionFactory);
        // 設置消息轉換器
        factory.setMessageConverter(jacksonJmsMessageConverter());
        factory.setPubSubDomain(true);
        factory.setSessionTransacted(true);
        factory.setAutoStartup(true);
        //開啓持久化訂閱
        factory.setSubscriptionDurable(true);
        factory.setClientId(applicationName);
        return factory;
    }

    /**
     * queue模式的ListenerContainer
     * @param activeMQConnectionFactory
     * @return
     */
    @Bean("jmsListenerContainerQueue")
    public JmsListenerContainerFactory<?> jmsListenerContainerQueue(ActiveMQConnectionFactory activeMQConnectionFactory,
                                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, activeMQConnectionFactory);
        // 設置消息轉換器
        factory.setMessageConverter(jacksonJmsMessageConverter());
        factory.setPubSubDomain(false);
        return factory;
    }

    /**
     * 消息轉換器
     * @return
     */
    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

}

提供者

/**
 * 隊列消息控制器
 * @author gourd.hu
 */
@RestController
@RequestMapping("/activeMq")
@Api(tags = "activeMq", description = "隊列消息控制器" )
public class ActiveMqController {

    /**
     * 注入存放消息的隊列,用於下列方法一
     */
    @Autowired
    private Queue queue;

    /**
     * 注入springboot封裝的工具類
     */
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @GetMapping("send")
    @ApiOperation(value = "發送消息到隊列")
    public BaseResponse send(@RequestParam("msg") String msg) {

        jmsMessagingTemplate.convertAndSend(queue, msg);
        return BaseResponse.ok("success!");
    }


    @Autowired
    private Topic topic;
 
    @GetMapping("/topic")
    @ApiOperation(value = "發送消息到主題")
    public BaseResponse handlerActiveMq(@RequestParam("msg")String  msg) {
        jmsMessagingTemplate.convertAndSend(topic, msg);
        return BaseResponse.ok("success!");
    }
 
}

消費者

@SendTo 加上此註解消費方法可以有返回值,否則只能爲void
/**
 * 消息消費
 *
 * @author gourdhu
 */
@Component
@Slf4j
public class ConsumerService {


    /**
     * 使用JmsListener配置消費者監聽的隊列,其中name是接收到的消息
     * @param message
     * @return
     */
    @JmsListener(destination = "gourd-queue",containerFactory = "jmsListenerContainerQueue")
    @SendTo("SQueue")
    public void handleMessage(final TextMessage message) throws JMSException {
        log.info("queue-consumer收到的報文爲:" + message.getText());
    }

    @JmsListener(destination = "gourd-topic",containerFactory = "jmsListenerContainerTopic")
    @SendTo("STopic")// 加上此註解可以有返回值,否則只能爲void
    public void receiveTopic(final TextMessage message) throws JMSException {
        log.info("topic-consumer收到的報文爲:" + message.getText());
//        if(true){
//            throw new BusinessException("測試消息重試");
//        }
    }
 
}

至此整合完成,經測試持久化和重試都是正常的。

===============================================

代碼均已上傳至本人的開源項目

spring-cloud-plus:https://blog.csdn.net/HXNLYW/article/details/104635673

 

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