ActivemqメッセージコンポーネントのパブリッシュおよびサブスクライブReDeliveryメッセージの再配信

ActiveMQ部門の有名なドアは、最も人気があり強力なオープンソースメッセージバスであるApacheによって作成されています。これは完全にJMS仕様に基づくメッセージコンポーネントであり、主流のSpring Framework、Spring Bootなどと簡単に統合できます。この記事では、Spring Boot統合を使用して、プロデューサーのメッセージ送信、コンシューマーのメッセージの消費、およびメッセージを実装します。 -配信。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-32-activemq-demo</artifactId>

    <dependencies>
        <!-- 实现对 ActiveMQ 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>

        <!-- 方便等会写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

ActiveMqProducer

package com.story.storyadmin.mq.active;

import com.alibaba.fastjson.JSONObject;
import com.story.storyadmin.mq.vo.MessageVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;

/**
 * @Description TODO
 * @Author huangd
 * @Date 2020-08-11
 **/
@Service
public class ActiveMqProducer {
    
    

    @Autowired
    private JmsMessagingTemplate jmsTemplate;

    public void syncSend(Integer id) {
    
    
        MessageVo messageVo = new MessageVo();
        messageVo.setMessage("hello world");
        messageVo.setMsgId(123456L);
        for (int i=0; i < 5; i++) {
    
    
            jmsTemplate.convertAndSend("first_queue", JSONObject.toJSONString(messageVo));
        }
    }
}


メッセージ消費者

package com.story.storyadmin.mq.active;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;

/**
 * @Description TODO
 * @Author huangd
 * @Date 2020-08-11
 **/
@Service
public class Customer {
    
    

    @JmsListener(destination="first_queue", concurrency = "2")
    public void customer(String message) {
    
    
        System.out.println("thread=" + Thread.currentThread().getId() + " receive msg is: " + message);
    }

}

package com.story.storyadmin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class StoryAdminApplication extends SpringBootServletInitializer {
    
    

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    
    
        return builder.sources(this.getClass());
    }

    public static void main(String[] args) {
    
    
        SpringApplication.run(StoryAdminApplication.class, args);
    }
}

spring:
  activemq:
    broker-url: tcp://你的虚拟机地址:61616
    user: admin
    password: admin

ユニットテストクラス

package com.story.storyadmin;

import com.story.storyadmin.mq.active.ActiveMqProducer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = StoryAdminApplication.class)
public class StoryAdminApplicationTests {
    
    
    @Autowired
    private ActiveMqProducer activeMqProducer;

	@Test
	public void contextLoads() throws IOException {
    
    
        activeMqProducer.syncSend(101);
        System.in.read();
	}
}

ここに画像の説明を挿入
2つのスレッドがメッセージを消費しているようです。これは、@ JmsListener(destination = "first_queue"、concurrency = "2")が構成リスナークラスに追加されているためです。

上記は通常の消費です。消費中に例外が発生した場合、activemqはデフォルトで消費を再配信します。
公式ウェブサイトでは、次の条件によりメッセージが再送されることが示されています。

  1. トランザクションセッションが使用され、rollback()が呼び出されます。
  2. トランザクションセッションは、commit()が呼び出される前に閉じられます。
  3. セッションはCLIENT_ACKNOWLEDGEを使用しており、Session.recover()が呼び出されます。
  4. クライアント接続がタイムアウトします(おそらく、実行中のコードは、構成されたタイムアウト期間よりも長くかかります)。

公式ウェブサイトアドレス:メッセージの再配信とDLQ処理

処理の例外をシミュレートするには、お客様に次の変更を加えます

@Service
public class Customer {
    
    

    @JmsListener(destination="first_queue", concurrency = "2")
    public void customer(String message) {
    
    
        throw new RuntimeException("customer error");
//        System.out.println("thread=" + Thread.currentThread().getId() + " receive msg is: " + message);
    }
}

再実行では、スプリングブート自動アセンブリ(ActiveMQAutoConfigurationエントリクラス)のために再試行することがわかります。デフォルトでは、1秒に1回、6回再試行ます。

Spring Bootの自動アセンブリ再試行戦略を使用したくない場合は、次のようにBeanをカスタマイズし、IOCを介してSpringコンテナーに注入できます。

ActiveMqConfig.java

package com.story.storyadmin.mq.active;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.RedeliveryPolicy;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;

import javax.annotation.Resource;

/**
 * @Description TODO
 * @Author huangd
 * @Date 2020-08-13
 **/
@Configuration
public class ActiveMqConfig {
    
    

    @Resource
    private ActiveMQProperties activeMQProperties;

    @Bean
    public RedeliveryPolicy redeliveryPolicy() {
    
    
        RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
        // 重试两次
        redeliveryPolicy.setMaximumRedeliveries(2);
        // 每隔2秒重试一次 
        redeliveryPolicy.setInitialRedeliveryDelay(2000L);
        return redeliveryPolicy;
    }


    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory(RedeliveryPolicy redeliveryPolicy) {
    
    
        ActiveMQConnectionFactory activeMQConnectionFactory =
                new ActiveMQConnectionFactory(activeMQProperties.getUser(), activeMQProperties.getPassword(), activeMQProperties.getBrokerUrl());

        activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
        return activeMQConnectionFactory;
    }

    @Bean
    public DefaultJmsListenerContainerFactory defaultJmsListenerContainerFactory(ActiveMQConnectionFactory activeMQConnectionFactory) {
    
    
        DefaultJmsListenerContainerFactory jmsListenerContainerFactory = new DefaultJmsListenerContainerFactory();
        jmsListenerContainerFactory.setConcurrency("2");
        jmsListenerContainerFactory.setConnectionFactory(activeMQConnectionFactory);
        jmsListenerContainerFactory.setSessionAcknowledgeMode(4);
        return jmsListenerContainerFactory;
    }

    @Bean
    public JmsTemplate jmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory) {
    
    
        JmsTemplate jmsTemplate = new JmsTemplate(activeMQConnectionFactory);
        jmsTemplate.setSessionAcknowledgeMode(4);
        return jmsTemplate;
    }
}

ActiveMqProducer.java

package com.story.storyadmin.mq.active;

import com.alibaba.fastjson.JSONObject;
import com.story.storyadmin.mq.vo.MessageVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;

/**
 * @Description TODO
 * @Author huangd
 * @Date 2020-08-11
 **/
@Service
public class ActiveMqProducer {
    
    

    @Autowired
    private JmsTemplate jmsTemplate;

    public void syncSend(Integer id) {
    
    
        MessageVo messageVo = new MessageVo();
        messageVo.setMessage("hello world " + id);
        messageVo.setMsgId(123456L);
        for (int i=0; i < 5; i++) {
    
    
            jmsTemplate.convertAndSend("first_queue", JSONObject.toJSONString(messageVo));
        }
    }

}


Customer.java

package com.story.storyadmin.mq.active;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;

/**
 * @Description TODO
 * @Author huangd
 * @Date 2020-08-11
 **/
@Service
public class Customer {
    
    

    @JmsListener(destination="first_queue", containerFactory = "defaultJmsListenerContainerFactory")
    public void customer(final TextMessage text, Session session) throws JMSException {
    
    
        try{
    
    
            String message = text.getText();
            System.out.println("thread=" + Thread.currentThread().getId() + " receive msg is: " + message);
            throw new RuntimeException("customer error");
//            text.acknowledge();
        }catch (Exception e) {
    
    
            session.recover();
        }
    }
}

アプリケーション起動クラスと@EnableConfigurationProperties({ActiveMQProperties.class})により、ActiveMQPropertiesクラスが有効になります。

最大再試行回数が正常に消費されていない場合は、デッドレターキューActiveMQ.DLQに入ります。
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/huangdi1309/article/details/107991123