ActiveMQ
Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;
由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。
优点
ActiveMQ 采用消息推送方式,所以最适合的场景是默认消息都可在短时间内被消费。
数据量越大,查找和消费消息就越慢,消息积压程度与消息速度成反比。
缺点
1.吞吐量低。由于ActiveMQ需要建立索引,导致吞吐量下降。这是无法克服的缺点,只要使用完全符合JMS规范的消息中间件,就要接受这个级别的TPS。
2.无分片功能。这是一个功能缺失,JMS并没有规定消息中间件的集群、分片机制。而由于ActiveMQ是为企业级开发设计的消息中间件,初衷并不是为了处理海量消息和高并发请求。如果一台服务器不能承受更多消息,则需要横向拆分。ActiveMQ官方不提供分片机制,需要自己实现
准备工作
首先我们要下载activemq的压缩包,下载地址:http://activemq.apache.org/download.html
直接解压,到bin文件夹中,选择适合自己系统的就好。
我的是64位,所以我选择win64,双击activemq.bat运行。
如何查看是否运行成功?
这个日志就告诉你了访问地址。
浏览器直接访问,输入账号密码admin/admin就好(默认密码),看到这个就代表成功了
接下来看代码
1、我们现在在做点对点模式,稍后会讲到发布订阅模式
创建springboot项目,直接点击next就好。
2、创建项目名之后,点击next
3、选择你需要的依赖,这里我们只选activeme 5 就好,然后一直点击next、finsh。
4、这时候我们已经创建好项目了,然后我们鼠标右键点击项目名,选择new/module,一样的流程创建生产者和消费者a、消费者b,最后我们项目结构是这样的:
5、我们先写producer消息生产者的代码,先来看下pom.xml文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.chenan</groupId>
<artifactId>producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>producer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
6、编写配置文件
// 项目端口号
server.port=8888
// 访问路径
server.servlet.context-path=/pro
// mq服务器的地址
spring.activemq.broker-url=tcp://192.168.15.183:61616
// 账号和密码
spring.activemq.user=admin
spring.activemq.password=admin
// 队列名称
queueName=publish.queue
topicName=publish.topic
7、编写我们自己的配置文件
package com.chenan.producer.configs;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
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 org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import javax.jms.Queue;
import javax.jms.Topic;
@Configuration
public class ActiveMQConfig {
@Value("${queueName}")
private String queueName;
@Value("${topicName}")
private String topicName;
@Value("${spring.activemq.user}")
private String usrName;
@Value("${spring.activemq.password}")
private String password;
@Value("${spring.activemq.broker-url}")
private String brokerUrl;
//创建消息队列
@Bean
public Queue queue(){
return new ActiveMQQueue(queueName);
}
//创建主题
@Bean
public Topic topic(){
return new ActiveMQTopic(topicName);
}
// 创建连接
@Bean
public ActiveMQConnectionFactory connectionFactory(){
return new ActiveMQConnectionFactory(usrName, password, brokerUrl);
}
//创建消费者监听器
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerQueue(ActiveMQConnectionFactory connectionFactory){
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setConnectionFactory(connectionFactory);
return bean;
}
//创建订阅者监听器
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ActiveMQConnectionFactory connectionFactory){
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
//设置为发布订阅方式, 默认情况下使用的生产消费者方式
bean.setPubSubDomain(true);
bean.setConnectionFactory(connectionFactory);
return bean;
}
}
8、现在我们来发送信息
package com.chenan.producer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Topic;
import java.util.Date;
import java.util.Queue;
@RestController
@RequestMapping("/producer")
public class ProducerController {
@Autowired
private JmsMessagingTemplate jms;
@Autowired
private Queue queue;
@Autowired
private Topic topic;
/**
* 发送queue消息
* @return
*/
@RequestMapping("/send")
public String queue(){
for (int i = 0; i < 10 ; i++){
// 参数为 :发送信息的队列名称,发送的信息
jms.convertAndSend("publish.queue", "queue"+i);
}
return "queue 发送成功";
}
/**
* queue发送的消息被消费后会发送回执信息
* @param msg
*/
@JmsListener(destination = "out.queue")
public void consumerMsg(String msg){
System.err.println(msg);
}
/**
* 发布topic
* @return
*/
@RequestMapping("/topic")
public String topic(){
for (int i = 0; i < 10 ; i++){
jms.convertAndSend(topic, "topic"+i);
}
return "topic 发送成功";
}
}
9、到这里就生产者就搞定了,有木有很简单?现在的项目结构是什么样子的呢?
现在我们来运行下试试,访问http://localhost:8888/pro/producer/send 回车
发送成功了,我们看下activemq服务器是什么样子
注意标红这一条,我们刚刚发送的队列名称叫做publish.queue,看名称就是这一条,然后看第二列,代表未被消费的信息数,意思是说我们刚刚的消息被推送到服务器上了,成功了。
10、那我们再来看下消费者,pom文件、配置文件、我们自己的配置文件都是一样的,我们就pass了,直接看代码。
创建QueueListener类,这个类主要用来监听一对一模式的消息
package com.chenan.customer_a.listener;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;
@Component
public class QueueListener {
// 监听消息
@JmsListener(destination = "publish.queue" ,containerFactory = "jmsListenerContainerQueue")
// 给另外一个队列发送此信息
@SendTo("out.queue")
public String receive(String message){
System.out.println("QueueListener:consumer-a 收到一条信息:"+message);
return "consumer-a:"+message;
}
}
创建TopicListener类,这个类主要用来监听发布订阅模式的消息
package com.chenan.customer_a.listener;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.Destination;
@Component
public class TopicListener {
@JmsListener(destination = "publish.topic",containerFactory = "jmsListenerContainerTopic")
public void recive(String text){
System.out.println("TopicListener: consumer-b 收到一条信息:"+text);
}
}
代码部分搞定了,我们现在一起来看下消费者a目前的结构:
我们先访问http://localhost:8888/pro/producer/send,然后看下队列服务器
我们发现队列中有20条未被消费的消息,那我们现在运行下消费者a:
可以看到,消费者a服务一旦运行,立刻接收到了20条消息,那现在队列服务器是什么样子呢?
可以看到,待消费消息变成0了,移除消息变为20了,消息被成功消费了,这时候,一对一模式也就搞定了,那什么是发布订阅呢?
11、我们比对着消费者a服务,再次创建一个消费者b服务,记得,端口号一定要改下,要不然会报错呦。直接运行即可,我们在上边的代码中其实已经实现了发布订阅模式了,浏览器直接访问http://localhost:8888/pro/producer/topic ,我们去查看两个消费者服务控制台
两个消费者服务都接收到了消息,大功告成。
总结:
一对一模式消息不被消费会一直存在于队列中,直到被消费为止,但发布订阅模式恰恰相反,消费者不能消费之前未消费到的信息,也就是说我们要运行消费者(订阅者)服务成功之后,生产者服务再产生消息,消费者(订阅者)才能成功消费消息。
好了,今天分享到此结束,本人新手小菜鸟,欢迎各路大神多多指导。