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はデフォルトで消費を再配信します。
公式ウェブサイトでは、次の条件によりメッセージが再送されることが示されています。
- トランザクションセッションが使用され、rollback()が呼び出されます。
- トランザクションセッションは、commit()が呼び出される前に閉じられます。
- セッションはCLIENT_ACKNOWLEDGEを使用しており、Session.recover()が呼び出されます。
- クライアント接続がタイムアウトします(おそらく、実行中のコードは、構成されたタイムアウト期間よりも長くかかります)。
公式ウェブサイトアドレス:メッセージの再配信と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に入ります。