RabbitAdmin类可以很好的操作RabbitMQ, 在Spring中直接进行注入即可
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory ConnectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
注意 : autoStartup必须要设置为true, 否则Spring容器就不会加载RabbitAdmin类
RabbitAdmin底层实现就是从Spring容器中获取Exchange, Binding, RoutingKey已及Queue的@Bean声明
然后RabbitAdmin底层使用RabbitTemplate的excute方法执行对应的声明, 修改, 删除等一系列RabbitMQ基础功能操作, 如添加一个交换机, 删除一个绑定, 清空一个队列等
添加Maven依赖 :
<properties>
<spring.version>4.3.20.RELEASEspring.version>
<junit.version>4.12junit.version>
<spring-rabbit.version>1.7.5.RELEASEspring-rabbit.version>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.amqpgroupId>
<artifactId>spring-rabbitartifactId>
<version>${spring-rabbit.version}version>
dependency>
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>3.6.5version>
dependency>
dependencies>
方式一 : 使用标签模式配置
<rabbit:connection-factory id="connectionFactory" host="192.168.72.138" port="5672" virtual-host="/" username="guest" password="guest"/>
<rabbit:admin id="rabbitAdmin" connection-factory="connectionFactory"/>
方式二: 使用Spring Bean的方式配置
<bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<property name="host" value="192.168.72.138"/>
<property name="port" value="5672"/>
<property name="virtualHost" value="/"/>
<property name="username" value="guest"/>
<property name="password" value="guest"/>
bean>
<bean id="rabbitAdmin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg ref="connectionFactory"/>
bean>
测试代码:
使用Spring集成Junit进行测试
// 用于Spring集成Junit, 添加到测试类上面
// @RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration("classpath:application.xml")
@Test
public void testRabbitAdmin() {
// 创建Direct模式Exchange
rabbitAdmin.declareExchange(new DirectExchange("test_spring_declare_exchange", false, false));
// 创建Topic模式Exchange
rabbitAdmin.declareExchange(new TopicExchange("test_spring_topic_exchange", false, false));
// 创建Fanout
rabbitAdmin.declareExchange(new FanoutExchange("test_spring_fanout_exchange", false, false));
// 创建队列
rabbitAdmin.declareQueue(new Queue("test_spring_direct_queue", false));
rabbitAdmin.declareQueue(new Queue("test_spring_topic_queue", false));
rabbitAdmin.declareQueue(new Queue("test_spring_fanout_queue", false));
// 可以直接创建绑定, new的Queue和Exchange必须在上面声明过
rabbitAdmin.declareBinding(
BindingBuilder
.bind(new Queue("test_spring_topic_queue", false))
.to(new TopicExchange("test_spring_topic_exchange", false, false))
.with("sping.*"));
rabbitAdmin.declareBinding(
BindingBuilder.bind(new Queue("test_spring_fanout_queue", false))
.to(new FanoutExchange("test_spring_fanout_exchange", false, false)));
}
配置类:
package com.qiyexue.annotation;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 基于Java类的方式配置
*
* @author 七夜雪
* @date 2018-12-19 20:28
*/
@Configuration
@ComponentScan("com.qiyexue.*")
public class RabbitConfig {
/**
* 配置ConnectionFactory
* @return
*/
@Bean
public ConnectionFactory connectionFactory(){
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setAddresses("192.168.72.138:5672");
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
return factory;
}
/**
* 声明RabbitAdmin
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
// 需要将AutoStartup设置为true
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
}
测试类:
测试类和基于xml配置的测试类是一样的, 只是在Spring启动的注解上修改一下, 改成加载类配置, 而不是加载配置文件配置,测试类声明如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={RabbitConfig.class})
public class RabbitAdminTest {
@Autowired
private RabbitAdmin rabbitAdmin;
}
<rabbit:topic-exchange name="topic002" durable="true"
auto-delete="false">
<rabbit:bindings>
<rabbit:binding pattern="huangquan.*" queue="queue002">rabbit:binding>
rabbit:bindings>
rabbit:topic-exchange>
<rabbit:queue name="queue002" durable="true" exclusive="false"
auto-delete="false">
rabbit:queue>
<rabbit:direct-exchange name="direct003" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="queue003" key="hongchen">rabbit:binding>
rabbit:bindings>
rabbit:direct-exchange>
<rabbit:queue name="queue003" durable="true" exclusive="false"
auto-delete="false">
rabbit:queue>
/**
* 针对消费者配置
* 1. 设置交换机类型
* 2. 将队列绑定到交换机
* FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念
* HeadersExchange :通过添加属性key-value匹配
* DirectExchange:按照routingkey分发到指定队列
* TopicExchange:多关键字匹配
*/
@Bean
public TopicExchange exchange001(){
TopicExchange exchange = new TopicExchange("topic001", false, false);
return exchange;
}
/**
* 声明队列
* @return
*/
@Bean
public Queue queue001(){
return new Queue("queue001", false);
}
/**
* 声明绑定
* @return
*/
@Bean
public Binding binding001(){
return BindingBuilder.bind(queue001()).to(exchange001()).with("biluo.*");
}
<bean id="rabbitTemlate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
<constructor-arg ref="connectionFactory">constructor-arg>
bean>
/**
* RabbitTemplate配置
* RabbitTemplate主要用于消息发送
* @param connectionFactory
* @return
*/
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
}
发送普通消息:
// 设置Message属性
MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put("name", "七夜雪");
messageProperties.getHeaders().put("age", 18);
Message message = new Message("听雪楼中听雪落".getBytes(), messageProperties);
// 使用Send方法必须传入message类型
rabbitTemplate.send("topic001", "biluo.test", message);
// 使用convertAndSend方法, 可以使用String类型, 或者Object类型消息, 会自动转换
rabbitTemplate.convertAndSend("topic002", "huangquan.test", "上穷碧落下黄泉", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
System.out.println("----------添加额外设置------------");
message.getMessageProperties().getHeaders().put("name", "黄泉");
message.getMessageProperties().getHeaders().put("company", "听雪楼");
return message;
}
});
自定义MessageListener:
package com.qiyexue.xml;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
/**
* 自定义MessageListener
*
* @author 七夜雪
* @date 2018-12-23 8:31
*/
public class MyMessageListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody());
System.out.println(msg);
}
}
<bean id="myMessageListener" class="com.qiyexue.xml.MyMessageListener"/>
<rabbit:listener-container connection-factory="connectionFactory"
auto-startup="true"
acknowledge="auto"
max-concurrency="5"
concurrency="1"
requeue-rejected="false">
<rabbit:listener ref="myMessageListener" queues="queue002,queue003"/>
rabbit:listener-container>
<bean id="simpleMessageListenerContainer"
class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="autoStartup" value="true"/>
<property name="acknowledgeMode" value="AUTO"/>
<property name="concurrentConsumers" value="1"/>
<property name="defaultRequeueRejected" value="false"/>
<property name="consumerTagStrategy" ref="myConsumerTag"/>
<property name="messageListener" ref="myMessageListener"/>
<property name="queueNames" value="queue001,queue002,queue003"/>
bean>
配置类中添加如下配置:
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 添加要监听的队列
// container.setQueues(queue001());
// 添加要监听的队列, 传入队列名, 和setQueues使用其中一个即可
container.setQueueNames("queue001","queue002", "queue003");
// 设置当前消费者格式
container.setConcurrentConsumers(1);
// 设置最大消费者个数
container.setMaxConcurrentConsumers(5);
// 是否重回队列
container.setDefaultRequeueRejected(false);
// 设置签收模式
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
container.setExposeListenerChannel(true);
// 设置消费者标签
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID().toString();
}
});
// 设置监听MessageListener
container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody());
System.out.println(msg);
}
});
return container;
}
测试直接使用RabbitTemplate发送消息即可
适配器模式监听消息
defaultListenerMethod默认监听方法名称, 用于设置监听方法名称, 默认handleMessage
Delegate委托对象, 委派设计模式, 实际真实的委托对象, 用于处理消息
queueOrTagToMethodName队列标识与方法名称组成的集合
- 可以一一进行队列与方法名称的匹配
- 队列与方法名称绑定, 即指定队列里的消息会被绑定的方法所接受处理
<bean id="messageListenerAdapter"
class="org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<ref bean="messageDelegate"/>
constructor-arg>
bean>
<bean id="messageDelegate" class="com.qiyexue.adapter.MessageDelegate"/>
/**
* 适配器方式 : 默认的方法名字的:handleMessage
* 可以自己指定方法名
* 也可以添加一个转换器, 将字节数组转换为String, 默认简单消息也是会转换成String的
*/
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDefaultListenerMethod("consumeMessage");
adapter.setMessageConverter(new TextMessageConverter());
container.setMessageListener(adapter);
/**
* 适配器模式, 队列与方法名绑定
*/
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
Map<String, String> queueToMethodMap = new HashMap<>();
queueToMethodMap.put("queue001", "queue1Method");
queueToMethodMap.put("queue002", "queue2Method");
adapter.setQueueOrTagToMethodName(queueToMethodMap);
container.setMessageListener(adapter);
测试方法 :
@Test
public void testSendMessage4Text() throws Exception {
//1 创建消息
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("text/plain");
Message message = new Message("听雪楼中听雪落...".getBytes(), messageProperties);
rabbitTemplate.send("topic001", "biluo.test", message);
rabbitTemplate.send("topic002", "huangquan.test", message);
}
在发送消息的时候, 正常情况下消息体是以二进制的数据方式进行传输, 如果希望内部进行转换, 或者指定自定义的转换器, 就需要用到MessageConverter
自定义常用转换器 : MessageConverter, 一般来讲,都需要实现这个接口
实现下面两个方法:
- toMessage : Java对象转换为Message
- fromMessage : Message对象转换成java对象
转换器类型
- Json转换器 : Jackson2JsonMessageConverter, 可以进行java对象的转换功能
- DefaultJackson2JavaTypeMapper映射器 : 可以进行java对象的映射
- 自定义二进制转换器 : 如图片,PDF, PPT等, 可以将多个转换器放到一个全局转换器ContentTypeDelegatingMessageConverter中
RabbitMQ入门与AMQP协议简介
RabbitMQ成员简介
RabbitMQ高级特性-消息可靠性投递
RabbitMQ高级特性-幂等性保障
RabbitMQ高级特性-Confirm确认消息
RabbitMQ高级特性-Return消息机制
RabbitMQ高级特性-消费端自定义监听
RabbitMQ高级特性-消费端限流
RabbitMQ高级特性-消费端ACK与重回队列
RabbitMQ高级特性-TTL队列/消息
RabbitMQ高级特性-死信队列(DLX)
Spring AMQP整合RabbitMQ
SpringBoot整合RabbitMQ
RabbitMQ集群架构模式介绍
从零开始搭建高可用RabbitMQ镜像模式集群
RabbitMQ集群恢复与故障转移
RabbitMQ-基础组件封装
Git代码地址
慕课网