1、服务安装
(1)RabbitMQ Docker安装
查询
docker search rabbitmq
下载镜像
选择的是可以访问web管理界面的tag
docker pull rabbitmq:management
创建容器
docker run -dit --name Myrabbitmq -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 -p 15678:15672 -p 5678:5672 rabbitmq:management
备注:15672是管理界面的端口,5672是服务的端口。这里顺便将管理系统的用户名和密码设置为admin admin
(2)ActiveMQ Docker安装
查询
docker search activemq
下载镜像
docker pull webcenter/activemq
查看镜像
docker image
创建容器
docker run -d --name activemq -p 61617:61616 -p 8162:8161 webcenter/activemq
- 61616是 activemq 的容器使用端口(映射为61617)
- 8161是 web 页面管理端口(对外映射为8162)
默认用户名和密码:admin/admin
修改用户名和密码
使用 docker exec -it activemq /bin/bash 进入 ActiveMQ
1.搜索文件,并找到
find / -name ‘jetty-realm.properties’
2,修改配置文件
vi jetty-realm.properties
3,修改重启服务
2、RabbitMQ使用
(1)消息提供端
POM依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置
spring:
rabbitmq:
# rabbitmq安装位置
host: 192.168.1.225
# rabbitmq的端口
port: 5678
# rabbitmq的用户名
username: admin
# rabbitmq的用户密码
password: 123456
# 配置虚拟机
virtual-host: /
# 开启消息确认机制 confirm 异步
publisher-confirm-type: correlated
# publisher-confirms: true # 之前的旧版本 开启消息确认机制的方式
# 开启return机制
publisher-returns: true
# 消息开启手动确认
listener:
direct:
acknowledge-mode: manual
创建 RabbitmqConfig
@SpringBootConfiguration
public class RabbitmqConfig {
/****************************Work 模型******************************************/
/**
* 配置一个工作模型队列
* work模型
* @return
*/
@Bean
public Queue queueWork1() {
return new Queue("queue_work");
}
/****************************Work 模型******************************************/
/****************************发布订阅模式******************************************/
/**
* 声明两个队列
* @return
*/
@Bean
public Queue queueFanout1() {
return new Queue("queue_fanout1");
}
@Bean
public Queue queueFanout2() {
return new Queue("queue_fanout2");
}
/**
* 准备一个交换机
* @return
*/
@Bean
public FanoutExchange exchangeFanout() {
return new FanoutExchange("exchange_fanout");
}
/**
* 将交换机和队列进行绑定
* @return
*/
@Bean
public Binding bindingExchange1() {
return BindingBuilder.bind(queueFanout1()).to(exchangeFanout());
}
@Bean
public Binding bindingExchange2() {
return BindingBuilder.bind(queueFanout2()).to(exchangeFanout());
}
/****************************发布订阅模式******************************************/
/****************************Topic 模型******************************************/
@Bean
public Queue queueTopic1() {
return new Queue("queue_topic1");
}
@Bean
public Queue queueTopic2() {
return new Queue("queue_topic2");
}
@Bean
public TopicExchange exchangeTopic() {
return new TopicExchange("exchange_topic");
}
@Bean
public Binding bindingTopic1() {
return BindingBuilder.bind(queueTopic1()).to(exchangeTopic()).with("topic.#");
}
@Bean
public Binding bindingTopic2() {
return BindingBuilder.bind(queueTopic2()).to(exchangeTopic()).with("topic.*");
}
/****************************Topic 模型******************************************/
/****************************confirm机制******************************************/
/**
* confirm 机制,创建一个队列
* @return
*/
@Bean
public Queue queueConfirm() {
return new Queue("queue_confirm");
}
/****************************confirm机制******************************************/
/****************************return机制******************************************/
@Bean
public Queue queueReturn() {
return new Queue("queue_return");
}
@Bean
public TopicExchange exchangeReturn() {
return new TopicExchange("exchange_return");
}
@Bean
public Binding bindingReturn() {
return BindingBuilder.bind(queueReturn()).to(exchangeReturn()).with("return.*");
}
/****************************return机制******************************************/
/****************************TTL队列、死信队列******************************************/
/**
* TTL 队列
* @return
*/
@Bean
public Queue queueTTL() {
Map<String, Object> map = new HashMap<>(1);
map.put("x-message-ttl", 10000);
return new Queue("queue_ttl", true, false, false, map);
}
/**
* 死信队列
* @return
*/
@Bean
public Queue queueDLX() {
Map<String, Object> map = new HashMap<>(2);
// 5秒后,消息自动变为死信
map.put("x-message-ttl", 5000);
map.put("x-dead-letter-exchange", "exchange_receive");
map.put("x-dead-letter-routing-key", "receive_key");
return new Queue("queue_dlx", true, false, false, map);
}
/**
* 死信交换机
* @return
*/
@Bean
public DirectExchange exchangeDLX() {
return new DirectExchange("exchange_dlx");
}
/**
* 死信队列绑定交换机
* @return
*/
@Bean
public Binding bindingDLX() {
return BindingBuilder.bind(queueDLX()).to(exchangeDLX()).with("receive_key");
}
/**
* 死信接收交换机
* @return
*/
@Bean
public DirectExchange exchangeReceive() {
return new DirectExchange("exchange_receive");
}
/**
* 接收死信的队列
* @return
*/
@Bean
public Queue queueReceive() {
return new Queue("queue_receive");
}
/**
* 交换机与队列绑定
* @return
*/
@Bean
public Binding bindingReceive() {
return BindingBuilder.bind(queueReceive()).to(exchangeReceive()).with("receive_key");
}
/****************************TTL队列、死信队列******************************************/
}
创建 Sender
@Component
public class Sender {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* work模型
* 一个发送,多个轮着接收
* @param msg
*/
public void sendWork(String msg){
/**
* 参数一:路由键
* 参数二:发送的消息
*/
this.rabbitTemplate.convertAndSend("queue_work", msg);
}
/**
* 向发布订阅模式里面发送消息
* 一个发送,多个同时接收
* @param msg
*/
public void sendPublish(String msg) {
/**
* 参数一:交换器名称
* 参数二:路由键
* 参数三:发送的消息
*/
rabbitTemplate.convertAndSend("exchange_fanout", "", msg);
}
/**
* 向topic模型发送数据
* 一个发送,多个同时接收(根据路由键)
* 消费者1 接收到了所有的数据
* 消费者2只接受到了一半(奇数)的数据
* @param msg
* @param id
*/
public void sendTopic(String msg,Integer id) {
if (id % 2 == 0) {
rabbitTemplate.convertSendAndReceive("exchange_topic", "topic.km.topic", msg + id);
} else {
rabbitTemplate.convertSendAndReceive("exchange_topic", "topic.km", msg + id);
}
}
/**
* confirm机制
* 提供端和消费端的Msg包路径必须保持一致
* @param id
*/
public void sendConfirm(Integer id) {
rabbitTemplate.convertAndSend("queue_confirm", new Msg(id, "km", "km123"), new CorrelationData("" + System.currentTimeMillis()));
rabbitTemplate.setConfirmCallback(confirmCallback);
}
/**
* 配置 confirm 机制
*/
private final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
/**
* @param correlationData 消息相关的数据,一般用于获取 唯一标识 id
* @param b true 消息确认成功,false 失败
* @param s 确认失败的原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if (b) {
System.out.println("confirm 消息确认成功..." + correlationData.getId());
} else {
System.out.println("confirm 消息确认失败..." + correlationData.getId() + " cause: " + s);
}
}
};
/**
* return机制
* 找不到路由则会返回消息
* @param msg
* @param id
*/
public void sendReturn(String msg,Integer id) {
if (id % 2 == 0) {
rabbitTemplate.convertAndSend("exchange_return", "return.km.km", msg + id);
} else {
rabbitTemplate.convertAndSend("exchange_return", "return.km", msg + id);
}
rabbitTemplate.setReturnCallback(returnCallback);
}
/**
* 配置 return 消息机制
*/
private final RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
/**
* return 的回调方法(找不到路由才会触发)
* @param message 消息的相关信息
* @param i 错误状态码
* @param s 错误状态码对应的文本信息
* @param s1 交换机的名字
* @param s2 路由的key
*/
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println(message);
System.out.println(new String(message.getBody()));
System.out.println(i);
System.out.println(s);
System.out.println(s1);
System.out.println(s2);
}
};
}
(2)消息消费端
POM依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置
spring:
rabbitmq:
# rabbitmq安装位置
host: 192.168.1.225
# rabbitmq的端口
port: 5678
# rabbitmq的用户名
username: admin
# rabbitmq的用户密码
password: 123456
# 配置虚拟机
virtual-host: /
# 开启消息确认机制 confirm 异步
publisher-confirm-type: correlated
# publisher-confirms: true # 之前的旧版本 开启消息确认机制的方式
# 开启return机制
publisher-returns: true
# 消息开启手动确认
listener:
direct:
acknowledge-mode: manual
消息监听
@Component
public class ReceiveListener {
/****************************Work 模型******************************************/
/**
* work模型
* 一个发送,多个轮着接收
*/
@RabbitListener(queues = "queue_work")
public void receiveMessage(String msg, Channel channel, Message message) {
// 只包含发送的消息
System.out.println("1接收到消息:" + msg);
// channel 通道信息
// message 附加的参数信息
}
@RabbitListener(queues = "queue_work")
public void receiveMessage2(Object obj, Channel channel, Message message) {
// 包含所有的信息
System.out.println("2接收到消息:" + obj);
}
/****************************Work 模型******************************************/
/****************************发布订阅模式******************************************/
/**
* 向发布订阅模式里面发送消息
* 一个发送,多个同时接收
*/
@RabbitListener(queues = "queue_fanout1")
public void receiveMsg1(String msg) {
System.out.println("队列1接收到消息:" + msg);
}
@RabbitListener(queues = "queue_fanout2")
public void receiveMsg2(String msg) {
System.out.println("队列2接收到消息:" + msg);
}
/****************************发布订阅模式******************************************/
/****************************Topic 模型******************************************/
/**
* 向topic模型发送数据
* 一个发送,多个同时接收(根据路由键)
* 消费者1 接收到了所有的数据
* 消费者2只接受到了一半(奇数)的数据
*/
@RabbitListener(queues = "queue_topic1")
public void receiveMsg1(String msg) {
System.out.println("消费者1接收到:" + msg);
}
@RabbitListener(queues = "queue_topic2")
public void receiveMsg2(String msg) {
System.out.println("消费者2接收到:" + msg);
}
/****************************Topic 模型******************************************/
/****************************confirm机制******************************************/
/**
* confirm机制
* 提供端和消费端的Msg包路径必须保持一致
*/
@RabbitListener(queues = "queue_confirm")
public void receiveMsg(Msg msg) {
System.out.println("接收到的消息为:" + msg);
}
/****************************confirm机制******************************************/
/****************************return机制******************************************/
/**
* return机制
* 找不到路由则会返回消息
*/
@RabbitListener(queues = "queue_return")
public void receiveMsg(String msg) {
System.out.println("接收的消息为:" + msg);
}
/****************************return机制******************************************/
}
3、ActiveMQ使用
(1)消息提供端
POM依赖
<!-- ActiveMQ的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
<!--消息队列连接池-->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
配置
activemq:
#activemq的url
broker-url: tcp://192.168.1.225:61617
#用户名
user: admin
#密码
password: admin
#是否使用线程池
pool:
#启用连接池
enabled: true
#连接池最大连接数
max-connections: 5
#空闲的连接过期时间,默认为30秒
idle-timeout: 30s
#是否信任所有包
packages:
trust-all: true
#默认情况下,activemq使用的是queue模式,如果要使用topic模式,必须设置为true
jms:
pub-sub-domain: true
启动类添加注解 @EnableJms
@EnableJms
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SeataOrderApplication {
public static void main(String[] args) {
SpringApplication.run(SeataOrderApplication.class, args);
}
}
创建Sender
@Component("Senders")
public class Sender {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
/**
* 将User对象转换成Message对象,并发送到queue或者topic
*
* @param msg
* @return
*/
public boolean produce(Msg msg) {
Destination destination = new ActiveMQQueue("queue01");
jmsMessagingTemplate.convertAndSend(destination, msg);
return true;
}
/**
* 延时发送的信息
* @param msg 发送的数据
* @param time 延时多少时间处理消息.
*/
public void delaySend(String msg, long time) {
//获取连接工厂
ConnectionFactory connectionFactory = jmsMessagingTemplate.getConnectionFactory();
try {
//获取连接
assert connectionFactory != null;
Connection connection = connectionFactory.createConnection();
connection.start();
//获取session, true开启事务,false关闭事务
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// 创建一个消息队列
Destination destination = session.createQueue("queue02");
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
TextMessage message = session.createTextMessage(msg);
//设置延迟时间 //AMQ_SCHEDULED_DELAY
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time * 1000L);
//发送
producer.send(message);
session.commit();
producer.close();
session.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将User对象转换成Message对象,并发送到queue或者topic
*
* @param msg
* @return
*/
public boolean produceTopic(Msg msg) {
Destination destination = new ActiveMQTopic("topic01");
jmsMessagingTemplate.convertAndSend(destination, msg);
return true;
}
}
(2)消息消费端
POM依赖
<!-- ActiveMQ的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
<!--消息队列连接池-->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
配置
activemq:
#activemq的url
broker-url: tcp://192.168.1.225:61617
#用户名
user: admin
#密码
password: admin
#是否使用线程池
pool:
#启用连接池
enabled: true
#连接池最大连接数
max-connections: 5
#空闲的连接过期时间,默认为30秒
idle-timeout: 30s
#是否信任所有包
packages:
trust-all: true
#默认情况下,activemq使用的是queue模式,如果要使用topic模式,必须设置为true
jms:
pub-sub-domain: true
启动类添加注解 @EnableJms
@EnableJms
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SeataBusinessApplication {
public static void main(String[] args) {
SpringApplication.run(SeataOrderApplication.class, args);
}
}
消息监听
@EnableJms
@Component
public class ReceiveListener {
@JmsListener(destination = "queue01", containerFactory = "queueContainerFactory")
public void customer(Msg msg) {
System.out.println("接收到的消息:");
System.out.println(msg);
}
@JmsListener(destination = "queue02", containerFactory = "queueContainerFactory")
public void customer2(String msg) {
System.out.println("接收延时消息:" + msg);
}
@JmsListener(destination = "topic01", containerFactory = "topicContainerFactory")
public void customer3(Msg msg) {
System.out.println("收到订阅消息:" + msg);
}
}
若要同时使用queue和topic,需添配置类,并在监听注解@JmsListener上添加containerFactory
@Configuration
public class ActivemqConfig {
/**
* 实现监听queue
*
* @param connectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory<?> queueContainerFactory(ConnectionFactory connectionFactory){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPubSubDomain(false);
// factory.setTaskExecutor(pool);
return factory;
}
/**
* 实现监听topic
*
* @param connectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory<?> topicContainerFactory(ConnectionFactory connectionFactory){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPubSubDomain(true);
// factory.setTaskExecutor(pool);
return factory;
}
}