一、概述
![img_5ee14fdb18c5f220e3a4ca5c3c0b1d3b.png](https://i-blog.csdnimg.cn/blog_migrate/67b3cca4cf956887f350f7eee474e6a7.png)
![img_847083ff7503e4a0312586e1166da323.png](https://i-blog.csdnimg.cn/blog_migrate/be9555bf675cae3d1c09494285d0f297.png)
![img_47265e24e86a09b07bc1bf079f7a22cd.png](https://i-blog.csdnimg.cn/blog_migrate/03545fab4c9e3726a41be88f509d7a2e.png)
![img_cba9e4f1caba3ef0df1a0a5c4f43d044.png](https://i-blog.csdnimg.cn/blog_migrate/17e7ee6e4c44cfcd68362d4502bbbe72.png)
![img_ce258e7583129d280a88c5308d0df634.png](https://i-blog.csdnimg.cn/blog_migrate/2195c087022a8848f0e43dcfd0784403.png)
![img_76280e7f7165e0726089547c36aac20e.png](https://i-blog.csdnimg.cn/blog_migrate/117c8b4289c4f93865f9825bba006f5c.png)
![img_efbf337b5b8ffd78a69920df4a6474de.png](https://i-blog.csdnimg.cn/blog_migrate/ec5caeaaed51b69d1f033708302a7954.png)
![img_594a9cef3e6121154c245a82c3800a45.png](https://i-blog.csdnimg.cn/blog_migrate/a1fc86193ed22fe590c4e517de414d82.png)
![img_5e6ebc0bb796513afc2407a7c9e2def0.png](https://i-blog.csdnimg.cn/blog_migrate/8447b0cb0801d176d146d8fa8822b876.png)
![img_eb9f5049294ba2cc7bfb4e0d276cbb8c.png](https://i-blog.csdnimg.cn/blog_migrate/7580e7a019d67863b50d85a6fe85d3e1.png)
![img_0bfd4996533021d9b22e1a6df438ab1a.png](https://i-blog.csdnimg.cn/blog_migrate/b1f409621160456e73ef168eceb2d0ce.png)
![img_b7a9e2aee9b2dbdb38051f63abb2b2d8.png](https://i-blog.csdnimg.cn/blog_migrate/a59ebdb41f35cde283f04f705bb31704.png)
四、SpringBoot+RabbitMQ整合
- 使用docker安装RabbitMQ
1)、使用docker pull 下载rabbitmq
[root@localhost ~]# docker pull registry.docker-cn.com/library/rabbitmq:3-management
3-management: Pulling from library/rabbitmq
683abbb4ea60: Already exists
30a58d97bcb5: Pull complete
...
- 启动rabbitMQ
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.docker-cn.com/library/redis latest 71a81cb279e3 9 days ago 83.4MB
registry.docker-cn.com/library/rabbitmq 3-management 500d74765467 9 days ago 149MB
mysql 5.7 66bc0f66b7af 9 days ago 372MB
[root@localhost ~]# docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq 500d74765467
7599303175cb42287d0f58c0b9d0db67070199670cad4f680f6348e41d6e2240
-
在浏览器输入:http://主机地址:15672 进入rabbitMQ登录页面
-
输入默认用户名:guest/guest 进入管理界面
![img_8169431777c288b9547d479bc3191819.png](https://i-blog.csdnimg.cn/blog_migrate/c6b345fbe9624e783d41605df1ab56fa.png)
![img_6b496e513431b8b14aa56bfb116a20ec.png](https://i-blog.csdnimg.cn/blog_migrate/c1e6aac51bbdb7fe53d46d7e74a72d6d.png)
![img_57739c25136eb924afcf306571931517.png](https://i-blog.csdnimg.cn/blog_migrate/f9f96b16b448e9dd1d795c37c10754d8.png)
- 搭建springboot+rabbit工程
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</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>
引入spring-boot-starter-amqp包后springboot帮我们自动配置:
- 执行RabbitAutoConfiguration
- 自动配置类会帮我们自动配置连接工厂、RabbitTemplate(给RabbitMQ发送和接受消息)、AmqpAdmin(RabbitMQ系统管理功能组件)
@Configuration
@ConditionalOnMissingBean({ConnectionFactory.class})
protected static class RabbitConnectionFactoryCreator {
protected RabbitConnectionFactoryCreator() {
}
@Bean
public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config) throws Exception {
RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
if(config.determineHost() != null) {
factory.setHost(config.determineHost());
}
factory.setPort(config.determinePort());
if(config.determineUsername() != null) {
factory.setUsername(config.determineUsername());
}
if(config.determinePassword() != null) {
factory.setPassword(config.determinePassword());
}
if(config.determineVirtualHost() != null) {
factory.setVirtualHost(config.determineVirtualHost());
}
if(config.getRequestedHeartbeat() != null) {
factory.setRequestedHeartbeat(config.getRequestedHeartbeat().intValue());
}
Ssl ssl = config.getSsl();
if(ssl.isEnabled()) {
factory.setUseSSL(true);
if(ssl.getAlgorithm() != null) {
factory.setSslAlgorithm(ssl.getAlgorithm());
}
factory.setKeyStore(ssl.getKeyStore());
factory.setKeyStorePassphrase(ssl.getKeyStorePassword());
factory.setTrustStore(ssl.getTrustStore());
factory.setTrustStorePassphrase(ssl.getTrustStorePassword());
}
if(config.getConnectionTimeout() != null) {
factory.setConnectionTimeout(config.getConnectionTimeout().intValue());
}
factory.afterPropertiesSet();
CachingConnectionFactory connectionFactory = new CachingConnectionFactory((com.rabbitmq.client.ConnectionFactory)factory.getObject());
connectionFactory.setAddresses(config.determineAddresses());
connectionFactory.setPublisherConfirms(config.isPublisherConfirms());
connectionFactory.setPublisherReturns(config.isPublisherReturns());
if(config.getCache().getChannel().getSize() != null) {
connectionFactory.setChannelCacheSize(config.getCache().getChannel().getSize().intValue());
}
if(config.getCache().getConnection().getMode() != null) {
connectionFactory.setCacheMode(config.getCache().getConnection().getMode());
}
if(config.getCache().getConnection().getSize() != null) {
connectionFactory.setConnectionCacheSize(config.getCache().getConnection().getSize().intValue());
}
if(config.getCache().getChannel().getCheckoutTimeout() != null) {
connectionFactory.setChannelCheckoutTimeout(config.getCache().getChannel().getCheckoutTimeout().longValue());
}
return connectionFactory;
}
}
-------------------------------------------------------------------------------------
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean({RabbitTemplate.class})
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
MessageConverter messageConverter = (MessageConverter)this.messageConverter.getIfUnique();
if(messageConverter != null) {
rabbitTemplate.setMessageConverter(messageConverter);
}
rabbitTemplate.setMandatory(this.determineMandatoryFlag());
Template templateProperties = this.properties.getTemplate();
Retry retryProperties = templateProperties.getRetry();
if(retryProperties.isEnabled()) {
rabbitTemplate.setRetryTemplate(this.createRetryTemplate(retryProperties));
}
if(templateProperties.getReceiveTimeout() != null) {
rabbitTemplate.setReceiveTimeout(templateProperties.getReceiveTimeout().longValue());
}
if(templateProperties.getReplyTimeout() != null) {
rabbitTemplate.setReplyTimeout(templateProperties.getReplyTimeout().longValue());
}
return rabbitTemplate;
}
------------------------------------------------------------------------------------------------
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnProperty(
prefix = "spring.rabbitmq",
name = {"dynamic"},
matchIfMissing = true
)
@ConditionalOnMissingBean({AmqpAdmin.class})
public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
- RabbitProperties 封装了RabbitMQ的所有配置
@ConfigurationProperties(
prefix = "spring.rabbitmq"
)
public class RabbitProperties {
private String host = "localhost";
private int port = 5672;
private String username;
private String password;
private final RabbitProperties.Ssl ssl = new RabbitProperties.Ssl();
private String virtualHost;
private String addresses;
private Integer requestedHeartbeat;
private boolean publisherConfirms;
private boolean publisherReturns;
private Integer connectionTimeout;
private final RabbitProperties.Cache cache = new RabbitProperties.Cache();
private final RabbitProperties.Listener listener = new RabbitProperties.Listener();
private final RabbitProperties.Template template = new RabbitProperties.Template();
private List<RabbitProperties.Address> parsedAddresses;
...
- application.properties配置
spring.rabbitmq.host=192.168.43.53
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
- 编写测试类
- 自定义MessageConverter
package com.pyy.rabbitmq.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by Administrator on 2018/7/7 0007.
*/
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
- Exchange.direct:点对点(单播模式)
发送消息:
/**
* 1、单播(点对点)
*/
@Test
public void direct() {
//Message需要自定构造一个:定义消息体内容和消息头:
//rabbitTemplate.send(exchange, routeKey, message);
// object默认当成消息体,只需要传入需要发送的内容,自动序列化发送给rabbitmq
// rabbitTemplate.convertAndSend(exchange, routeKey, object);
User user = new User();
user.setUsername("张三");
user.setPassword("12312321");
// msg 对象被默认(SimpleMessageConverter -- byte[])序列化后发送出去
// 通过自定义:MessageConverter 实现JSON序列化
rabbitTemplate.convertAndSend("exchange.direct", "pyy.news", user);
}
![img_df47406f1d059c5f1a13a2dd2282329b.png](https://i-blog.csdnimg.cn/blog_migrate/dd21611df73ffe37d0c0df29c6cc77d5.png)
只有Queue:pyy.news 该消息队列接收到消息,其他队列不能接收到该消息。
消息内容如下:
![img_df0aa2f0592fac98b700c59d768a38b4.png](https://i-blog.csdnimg.cn/blog_migrate/50e4a31221884c3a3bc0de8b098adaf0.png)
接受消息:
/**
* 接受数据
*/
@Test
public void receve() {
Object obj = rabbitTemplate.receiveAndConvert("pyy.news");
System.out.println(obj.getClass());
System.out.println(obj);
if(obj instanceof User){
User u = (User) obj;
System.out.println(u.getUsername());
System.out.println(u.getPassword());
}
}
结果:
class com.pyy.rabbitmq.User
com.pyy.rabbitmq.User@4c27d39d
张三
12312321
- Exchange.fanout:广播模式
/**
* 2、广播
*/
@Test
public void fanout() {
//Message需要自定构造一个:定义消息体内容和消息头:
//rabbitTemplate.send(exchange, routeKey, message);
// object默认当成消息体,只需要传入需要发送的内容,自动序列化发送给rabbitmq
// rabbitTemplate.convertAndSend(exchange, routeKey, object);
User user = new User();
user.setUsername("李四");
user.setPassword("123456");
// fanout模式路由键不用指定,所有绑定到这个交换机的消息队列都能接受到该消息
rabbitTemplate.convertAndSend("exchange.fanout", "", user);
}
注意:fanout模式路由键不用指定,所有绑定到这个交换机的消息队列都能接受到该消息
![img_caa293e6d39222a9a28fd1a69548d8d2.png](https://i-blog.csdnimg.cn/blog_migrate/ba56e4ca31a6313a26b9938cd2b21f9d.png)
![img_6bff3ba6dc752c864eb24f3a0d01374e.png](https://i-blog.csdnimg.cn/blog_migrate/df70245e6da1c525ee121ae5761fa99e.png)
- Exchange.topic 主题模式
/**
* 3、topic
*/
@Test
public void topic() {
//Message需要自定构造一个:定义消息体内容和消息头:
//rabbitTemplate.send(exchange, routeKey, message);
// object默认当成消息体,只需要传入需要发送的内容,自动序列化发送给rabbitmq
// rabbitTemplate.convertAndSend(exchange, routeKey, object);
User user = new User();
user.setUsername("王五");
user.setPassword("123456");
// topic模式路由键只有和exchange绑定的路由键规则匹配,对应的消息队列就能收到消息
rabbitTemplate.convertAndSend("exchange.topic", "*.news", user);
}
![img_1b91116401511074772a93b280fc064c.png](https://i-blog.csdnimg.cn/blog_migrate/35af35e153534862af8d03051295a2b9.png)
![img_d6d920642f31eab6ca40222e9c935bc2.png](https://i-blog.csdnimg.cn/blog_migrate/34a4639a8620cafec0bdb1e1a2a1877c.png)
SpringBoot高级-消息-@RabbitListener&@EnableRabbit监听
- 开启RabbitListener注解支持
@EnableRabbit // 开启基于注解的RabbitMQ
@SpringBootApplication
public class Springboot02RabbitmqApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot02RabbitmqApplication.class, args);
}
}
- 使用@RabbitListener注解完成消息接收
package com.pyy.rabbitmq.service;
import com.pyy.rabbitmq.model.User;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
/**
* Created by Administrator on 2018/7/8 0008.
*/
@Service
public class UserService {
/**
* 自动监听消息队列:pyy.news
* @param user
*/
@RabbitListener(queues = {"pyy.news"})
public void receive(User user) {
System.out.println("收到消息:"+user);
}
//结果: 收到消息:User{username='张三', password='12312321'}
/**
* 自动监听消息队列:pyy.news
* @param message
*/
@RabbitListener(queues = {"pyy"})
public void receive(Message message) {
System.out.println("消息头:"+message.getMessageProperties());
System.out.println("消息体:"+message.getBody());
}
}
系统会自动监听指定名称的消息队列,只有有消息自动消费。
AmqpAdmin 管理rabbitmq相关操作:
package com.pyy.rabbitmq;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot02RabbitmqApplicationTests1 {
@Autowired
RabbitTemplate rabbitTemplate;
@Autowired
AmqpAdmin amqpAdmin;
/**
* 创建交换机:exchange
*/
@Test
public void createExchange() {
amqpAdmin.declareExchange(new DirectExchange("amqpadmin.DirectExchange"));
amqpAdmin.declareExchange(new FanoutExchange("amqpadmin.FanoutExchange"));
amqpAdmin.declareExchange(new TopicExchange("amqpadmin.TopicExchange"));
System.out.println("创建完毕");
}
/**
* 创建队列:queye
*/
@Test
public void createQueue() {
amqpAdmin.declareQueue(new Queue("amqpadmin.queue", true));
System.out.println("创建完毕");
}
/**
* 创建绑定规则:binding
*/
@Test
public void createBinding() {
/**
String destination: 目的地
String exchange: 交换机
String routingKey: 路由键
Map<String, Object> arguments:
Binding.DestinationType destinationType:目的地类型
*/
amqpAdmin.declareBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE, "amqpadmin.DirectExchange", "amqp.haha", null));
System.out.println("创建完毕");
}
}
![img_f640343637e73e4e35fc7d1c4ec0effd.png](https://i-blog.csdnimg.cn/blog_migrate/85e65f9cd381120f799ed09a562ad0b7.png)
![img_91397b68ececc01cb826693cbfc2ee53.png](https://i-blog.csdnimg.cn/blog_migrate/ee2b53d4b037870ac5fd660799be2477.png)
![img_54341075d5cc96d610e85c21f6c16fb7.png](https://i-blog.csdnimg.cn/blog_migrate/972dee5b734a8da67608902611a5e44c.png)