1、Spring Boot 和 ActiveMQ 、RabbitMQ 简介

  最近因为公司的项目需要用到 Spring Boot , 所以自学了一下, 发现它与 Spring 相比,最大的优点就是减少了配置, 看不到 xml 文件的配置, 而是用 appplication.yml 或者 application.propertites 文件来代替 , 再也不用配置 tomcat 环境了, 因为 spring boot 已经将 tomcat 环境整合到里面了。入门可以去 http://spring.io 官网, 上面有一系列介绍 。

  本次项目开发中还用到了 ActiveMQ 和 RabbitMQ , 这是两个消息队列,我直到完成模块都不能真正理解消息队列。 关于消息队列的定义和使用场景这篇博客写得十分清楚:

https://blog.csdn.net/KingCat666/article/details/78660535,几个不同的消息队列之间的比较 : https://blog.csdn.net/linsongbin1/article/details/47781187。我负责的任务是 Spring Boot 监听 ActiveMQ 中特定的 topic,并将消息使用 RabbitMq 发布出去。

2、配置环境

  2.1 ·使用 maven 构建 Spring Boot 运行环境, 在 pom.xml 文件中加入如下依赖:

<properties>
<project.build.sourceEncoding>UTF8
</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Springboot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<!-- rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.0.7.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.0.7.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.0.7.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-maven-plugin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

  2.2 下载并安装配置 active mq 和 rabbitmq 的运行环境

    activemq下载地址如下 : http://activemq.apache.org/download-archives.html

rabbitmq 是使用 erlang 写的, 所以先安装 erlang 环境, 再安装 rabbitmq-server, 现在我将这三个文件整合到了一起, 方便下载 :

链接: https://pan.baidu.com/s/1qdzMpqFwxR78rW7-ABpbCA  提取码: 7aqf 。下载完成以后, 其中比较复杂的是安装 erlang ,安装完以后新建 ERLAGN_HOME 添加到环境变量。                                  将 %ERLANG_HOME%\bin 添加到 path,然后安装 rabbit-server.exe, 安装完以后在进入 rabbit-server\sbin 目录下, 进入命令行,输入 rabbitmq-plugins enable rabbitmq_management 完成安装,

打开 sbin 目录,双击rabbitmq-server.bat , 启动成功之后访问 http://localhost:15672,默认账号密码都属 guest 。

将下载的 activemq 解压到某个目录下,进入该目录输入 cmd ,敲击 bin\activemq start , 有可能会报错,具体错误查看 data\activemq.log 文件。环境搭建成功以后, 开始干!

3、构建项目

  3、1 新建配置文件:

    新建 application.yml 文件,输入:

com:
mqtt:
inbound:
url: tcp://127.0.0.1:1883
clientId: familyServerIn
topics: hello,topic
outbound:
urls: tcp://127.0.0.1:1883
clientId: familyServerOut
topic: topic1 spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: root
password: root
virtualHost: /
listener:
concurrency: 2
max-concurrency: 2
main:
web-application-type: none
mqtt:
username: admin
#MQTT-密码
password: admin
#MQTT-服务器连接地址,如果有多个,用逗号隔开,如:tcp://127.0.0.1:61613,tcp://192.168.2.133:61613
url: tcp://127.0.0.1:1883
#MQTT-连接服务器默认客户端ID
client:
id: mqttId
#MQTT-默认的消息推送主题,实际可在调用接口时指定
default:
topic: topic
#连接超时
completionTimeout: 3000

  3.2 新建配置类 MQttSenderConfig.java

在这里主要配置了 connectionFactory 和 channelFactory , 值得注意的是在方法 handler() 里面通过监听信道 mqttOutboundChannel 获得了 topic 并将其转发给 RabbitMQ 队列中, topicSender.send(message.getPayload().toString()); 这一行代码将消息发送到 RabbitMQ 队列中 、/*

/**
* 〈一句话功能简述〉<br>
* 〈MQTT发送消息配置〉
*
* @author root
* @create 2018/12/20
* @since 1.0.0
*/
@Configuration
@IntegrationComponentScan
public class MqttSenderConfig { @Value("${spring.mqtt.username}")
private String username; @Value("${spring.mqtt.password}")
private String password; @Value("${spring.mqtt.url}")
private String hostUrl; @Value("${spring.mqtt.client.id}")
private String clientId; @Value("${spring.mqtt.default.topic}")
private String defaultTopic; @Value("${spring.mqtt.completionTimeout}")
private int completionTimeout ; //连接超时 @Autowired
private TopicSender topicSender; @Bean
public MqttConnectOptions getMqttConnectOptions(){
MqttConnectOptions mqttConnectOptions=new MqttConnectOptions();
mqttConnectOptions.setUserName(username);
mqttConnectOptions.setPassword(password.toCharArray());
mqttConnectOptions.setServerURIs(new String[]{hostUrl});
mqttConnectOptions.setKeepAliveInterval(2);
return mqttConnectOptions;
} @Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(getMqttConnectOptions());
return factory;
} //mqttOutboundChannel
@Bean
@ServiceActivator(inputChannel = "mqttOutboundChannel")
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId, mqttClientFactory());
messageHandler.setAsync(true);
messageHandler.setDefaultTopic(defaultTopic);
return messageHandler;
} @Bean
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
} //接收通道
@Bean
public MessageChannel mqttInputChannel() {
return new DirectChannel();
} //配置client,监听的topic
@Bean
public MessageProducer inbound() {
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(clientId+"_inbound", mqttClientFactory(),
"topic","hello");
adapter.setCompletionTimeout(completionTimeout);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(1);
adapter.setOutputChannel(mqttOutboundChannel());
return adapter;
} //通过通道获取数据 @Bean
@ServiceActivator(inputChannel = "mqttOutboundChannel")
public MessageHandler handler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
// String type = topic.substring(topic.lastIndexOf("/")+1, topic.length());
if("hello".equalsIgnoreCase(topic)){
System.out.println("hello,fuckXX," + message.getPayload().toString());
topicSender.send(message.getPayload().toString());
}else if("topic".equalsIgnoreCase(topic)){
System.out.println("topic,fuckXX," + message.getPayload().toString());
topicSender.send(message.getPayload().toString());
}
}
};
} }

  3.2 新建配置类 RabbitConfig.java

配置了两个队列 rabbittopic 和 rabbittopic.queue2 , 申明了消息交换器 topicExchange, 通过 key 来绑定, 关于 key 和 路由绑定参考这篇文章 : https://www.jianshu.com/p/04f443dcd8bd 。

@Configuration
public class RabbitConfig implements RabbitListenerConfigurer { //声明队列
@Bean
public Queue queue1() {
return new Queue("rabbitopic", true); // true表示持久化该队列
} @Bean
public Queue queue2() {
return new Queue("rabbitopic.queue2", true);
} //声明交互器
@Bean
TopicExchange topicExchange() {
return new TopicExchange("topicExchange");
} //绑定
@Bean
public Binding binding1() {
return BindingBuilder.bind(queue1()).to(topicExchange()).with("key.1");
} @Bean
public Binding binding2() {
return BindingBuilder.bind(queue2()).to(topicExchange()).with("key.#");
} @Bean
public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(new MappingJackson2MessageConverter());
return factory;
} //queue listener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// factory.setPrefetchCount(5);//指定一个请求能处理多少个消息,如果有事务的话,必须大于等于transaction数量.
factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
//MANUAL:将ACK修改为手动确认,避免消息在处理过程中发生异常造成被误认为已经成功消费的假象。
//factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
} @Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(myHandlerMethodFactory());
}
}

  3.3 新建MqttGateway.java

  新建 MqttGateWay 接口,设置默认的信道 。

import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header; @MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {
void sendToMqtt(String data,@Header(MqttHeaders.TOPIC) String topic);
}

余下代码就不再一一往上贴了 : 具体 demo:https://github.com/blench/mqtt.git

4、遇到的错误及解决办法

    1、发送数据后 rabbitmq  一直在接收数据,原因是监听 RabbitMQ 队列消息的方法写错了, 例如:

 @RabbitListener(queues = "rabbitopic")
public void processMessage1(String msg) {
// Message message = rabbitTemplate.receive(10000);
System.out.println(" 接收到来自rabbitopic队列的消息:" + msg);
return;
}

接收监听的方法不能有返回值, 只能为 void .

  2、配置错误, 中途有一次启动失败,是由于代码的配置问题。

最后启动项目, 在 active mq 中新建 topic 和 hello 主题 , 添加测试内容发送。 控制台下可打印出相应的消息 。

5、总结

  虽然这次匆匆忙忙写完了代码,但是对于 RabbitMQ 和 ActiveMQ 只是有了初步的了解, 未来的工作中还会继续学习的 。

参考文档:

https://www.jianshu.com/p/6ca34345b796

https://www.jianshu.com/p/db8391dc1f63

http://blog.sina.com.cn/s/blog_7479f7990100zwkp.html

Spring Boot 监听 Activemq 中的特定 topic ,并将数据通过 RabbitMq 发布出去的更多相关文章

  1. spring boot 监听容器启动

    /** * 在容器启动的时候 加载没问完成的消息重发 * @author zhangyukun * */ @Component @Slf4j public class LoadMessageListe ...

  2. spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情

    <spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...

  3. 【ActiveMQ】2.spring Boot下使用ActiveMQ

    在spring boot下使用ActiveMQ,需要一下几个条件 1.安装并启动了ActiveMQ,参考:http://www.cnblogs.com/sxdcgaq8080/p/7919489.ht ...

  4. Spring事件监听Demo

    Spring事件监听实现了观察者模式.本Demo在junit4测试环境中实现 主要有三个类事件类.监听器类.事件发布类(入口) 事件类必须继承 ApplicationEvent,代码如下: impor ...

  5. Spring事件监听机制源码解析

    Spring事件监听器使用 1.Spring事件监听体系包括三个组件:事件.事件监听器,事件广播器. 事件:定义事件类型和事件源,需要继承ApplicationEvent. package com.y ...

  6. js 实时监听input中值变化

    注意:用到了jquery需要引入jquery.min.js. 需求: 1.每个地方需要分别打分,总分为100; 2.第一个打分总分为40; 3.第二个打分总分为60. 注意:需要判断null.&quo ...

  7. oracle11g的监听配置文件中的program和env两个配置,必须干掉,客户端才能正常连接

    oracle11g的监听配置文件中的program和env两个配置,必须干掉,客户端才能正常连接 oracle11g的监听配置文件中的program和env两个配置,必须干掉,客户端才能正常连接 or ...

  8. vue 监听对象里的特定数据

    vue  监听对象里的特定数据变化 通常是这样写的,只能监听某一个特定数据 watch: { params: function(val) { console.log(val) this.$ajax.g ...

  9. Fragment-如何监听fragment中的回退事件与怎样保存fragment状态

    一.如何监听Fragment中的回退事件 1.问题阐述 在Activity中监听回退事件是件非常容易的事,因为直接重写onBackPressed()函数就好了,但当大家想要监听Fragment中的回退 ...

随机推荐

  1. 《阿里巴巴Java开发手册1.4.0》阅读总结与心得(二)

    (六)并发处理 12. [推荐] 在并发场景下, 通过双重检查锁(double-checked locking) 实现延迟初始化的优化问题隐患(可参考 The "Double-Checked ...

  2. C#开发BIMFACE系列13 服务端API之获取转换状态

    系列目录     [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列12 服务端API之文件转换>中详细介绍了7种文件转换的方法.发起源文件/模型转换后,转换过程可能成功 ...

  3. ssh三大框架的认识

    一.SSH三大框架的概述 ssh为 struts+spring+hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架.  集成SSH框架的系统从职责上分为四层:表示层.业务逻辑层 ...

  4. 共价大爷游长沙 lct 维护子树信息

    这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边. 某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的. 现在我们要判断所有的路径是不是都经过 u -> v 我们以u为 ...

  5. ACM-ICPC 2017 Asia Urumqi:A. Coins(DP) 组合数学

    Alice and Bob are playing a simple game. They line up a row of nn identical coins, all with the head ...

  6. VS2017 之 MYSQL实体数据模

    Photon Server 和 Unity3D 数据交互: Photon Server 服务端编程 Unity3D 客户端编程 VS2017 之 MYSQL实体数据模 一.新建数据库连接后,点击下一步 ...

  7. [Swoole入门到进阶] [精选公开课] Swoole服务器-Server的四层生命周期

    PHP 完整生命周期 执行PHP文件 PHP扩展模块初始化(MINIT) PHP扩展请求初始化(RINIT) 执行 PHP 逻辑 PHP扩展请求结束(RSHUTDOWN) PHP脚本清理 PHP扩展模 ...

  8. 基于单细胞测序数据构建细胞状态转换轨迹(cell trajectory)方法总结

    细胞状态转换轨迹构建示意图(Trapnell et al. Nature Biotechnology, 2014) 在各种生物系统中,细胞都会展现出一系列的不同状态(如基因表达的动态变化等),这些状态 ...

  9. Flink文章测试

    Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 ...

  10. fastjson对象,JSON,字符串,map之间的互转

    1.对象与字符串之间的互转 将对象转换成为字符串 String str = JSON.toJSONString(infoDo); 字符串转换成为对象 InfoDo infoDo = JSON.pars ...