这一篇博客,来学习 ActiveMQ 的发布订阅模式 Topics。
首先我们要明白一点,发布订阅模式下,必须先订阅消息,然后发布消息后才能收到。相当于我们平时订鲜奶,必须先预定了,快递员才每天送鲜奶上门。
我们创建一个新项目,ActiveMQTopic
然后在项目中创建两个模块module,分别是:producer 和 consumer。代码结构如下图
在父级的 pom.xml (即最外面的 pom)加入如下依赖:
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>ActiveMQTopic</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>producer</module>
<module>consumer</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!--Spring boot 集成包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
接下来,我们先开发 consumer 模块的代码。注意,我们不需要在 consumer 和 producer 的 pom.xml 添加依赖了,直接引用父级的就可以了。
consumer 模块的 bootstrap.yml 的配置如下:注意,必须在配置文件里手动开启【发布订阅模式】,否则无法监听到消息。默认是关闭的。
spring:
activemq:
broker-url: tcp://127.0.0.1:61616
user: admin
password: admin
# 消费者端需要手动开启【发布订阅模式】
jms:
pub-sub-domain: true
# ActiveMQ 的队列名
topicsName: myTopicsName
# 将SpringBoot项目作为单实例部署调试时,不需要注册到注册中心
eureka:
client:
fetch-registry: false
register-with-eureka: false
然后编写监听类:TopicsConsumer,代码如下:
package com.test.consumer;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
/**
* @author biandan
* @description 发布订阅模式消息生产者
* @signature 让天下没有难写的代码
* @create 2021-03-21 下午 10:55
*/
@Component
public class TopicsConsumer {
@JmsListener(destination = "${topicsName}")
public void receive(String msg) {
System.out.println("消费者收到消息:" + msg);
}
}
最后编写启动类:TopicsConsumerApplication,代码如下:
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author biandan
* @signature 让天下没有难写的代码
* @create 2021-03-19 上午 12:07
*/
@SpringBootApplication
@EnableEurekaClient
public class TopicsConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(TopicsConsumerApplication.class, args);
}
}
这时候,启动 consumer 的启动类,控制台输出如下信息
然后到 ActiveMQ 管理后台查看:
说明有消费者订阅成功了。
我们为了模拟多个消费者订阅成功,需要修改一下配置。具体步骤如下:
1、点击IDEA右上角的启动类配置,如截图:
去掉右上角的勾选【Single instance only】,就可以启动多个实例了。
然后我们再启动一次 consumer 的启动类,一共启动3个消费者实例。
我们再到 ActiveMQ 管理后台查看,看到有3个消费者已经订阅了。
OK,我们接下来开发生产者模块。
生产者模块的 pom.xml 也不用添加任何依赖,直接使用父级的依赖即可。
producer 模块的 bootstrap.yml 配置文件如下:
spring:
activemq:
broker-url: tcp://127.0.0.1:61616
user: admin
password: admin
# ActiveMQ 的队列名
topicsName: myTopicsName
server:
port: 8080
# 将SpringBoot项目作为单实例部署调试时,不需要注册到注册中心
eureka:
client:
fetch-registry: false
register-with-eureka: false
配置类:TopicsConfig 代码如下:注意,注册的 Bean 是使用 ActiveMQTopic,而不是 ActiveMQTempTopic。
package com.test.config;
import org.apache.activemq.command.ActiveMQTempTopic;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.jms.Topic;
/**
* @author biandan
* @signature 让天下没有难写的代码
* @create 2021-03-19 下午 11:23
*/
@Configuration
public class TopicsConfig {
/**
* 获取配置文件的队列名
*/
@Value("${topicsName}")
private String topicsName;
/**
* 注册 jms的队列到 Spring 容器
* @return
*/
@Bean
public Topic registerTopics(){
return new ActiveMQTopic(topicsName);
}
}
生产者核心代码类:TopicsProducer 如下:
package com.test.consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.jms.Topic;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author biandan
* @description 发布订阅模式消息生产者
* @signature 让天下没有难写的代码
* @create 2021-03-21 下午 10:55
*/
@EnableScheduling
@Component
public class TopicsProducer {
private final static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
@Autowired
private JmsMessagingTemplate template;
@Autowired
private Topic topic;
//每2秒执行一次方法,产生一条消息
@Scheduled(fixedDelay = 1000 * 2)
public void sendMsg() {
String msg = "【发布订阅模式】产生一条消息:" + SDF.format(new Date());
System.out.println(msg);
template.convertAndSend(topic, msg);
}
}
最后,创建生产者的启动类:TopicsProducerApplication 代码如下:
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author biandan
* @signature 让天下没有难写的代码
* @create 2021-03-19 上午 12:07
*/
@SpringBootApplication
@EnableScheduling //启用任务调度
@EnableEurekaClient
public class TopicsProducerApplication {
public static void main(String[] args) {
SpringApplication.run(TopicsProducerApplication.class, args);
}
}
OK,我们启动生产者的启动类,看下控制台输出:每隔2秒生产一条消息。
然后到3个消费者的控制台看输出的内容:3个消费者的控制台都接收到了相同的消息。
最后到 ActiveMQ 管理后台查看:
消费者一共有3个,消息产生了51条,一共被消费了 51 × 3 = 153 次。
本文源代码:链接: https://pan.baidu.com/s/16oPirBLlRV1FxLY3G2i72A 提取码: xrje