POM文件中
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
通过bean的方式,将RabbitAdmin注入到容器中
/**
* 在配置文件中,将RabbitAdmin加载到spring容器中
*/
@Configuration
@ComponentScan({"com.atguigu.rabbit.rabbitmqtest.spring.*"})
public class RabbitMQConfig {
/**
* 配置连接工厂
*/
@Bean
public ConnectionFactory connectionFactory(){
CachingConnectionFactory factory=new CachingConnectionFactory();
factory.setAddresses("192.168.1.60:5672");
factory.setVirtualHost("/user_db");
factory.setUsername("users");
factory.setPassword("123");
return factory;
}
/**
* setAutoStartup必须设置为true。这样容器启动后,才会加载rabbitadmin
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
RabbitAdmin rabbitAdmin=new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
}
在配置文件中,声明交换机,队列。将队列和交换机进行绑定
@Configuration
@ComponentScan({"com.atguigu.rabbit.rabbitmqtest.spring.*"})
public class RabbitMQConfig {
/**
* 配置连接工厂
*/
@Bean
public ConnectionFactory connectionFactory(){
CachingConnectionFactory factory=new CachingConnectionFactory();
factory.setAddresses("192.168.1.60:5672");
factory.setVirtualHost("/user_db");
factory.setUsername("users");
factory.setPassword("123");
return factory;
}
/**
* setAutoStartup必须设置为true。这样容器启动后,才会加载rabbitadmin
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
RabbitAdmin rabbitAdmin=new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
/**
* SpringAMQP声明队列、交换机、绑定
*/
//声明Fanout交换机
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("fanout_exchange_springAMQP",false,false);
}
//声明一个队列
@Bean
public Queue queue001(){
return new Queue("queue001_name",true);//队列持久化
}
//队列和交换机绑定
@Bean
public Binding binding(){
return BindingBuilder.bind(queue001()).to(fanoutExchange());
}
//声明topic交换机
@Bean
public TopicExchange topicExchange(){
return new TopicExchange("topic_exchange_springAMQP",false,true);
}
@Bean
public Queue queue002(){
return new Queue("queue002_name",true);
}
//将002队列绑定到topic交换机上
@Bean
public Binding binding2(){
return BindingBuilder.bind(queue002()).to(topicExchange()).with("spring.#");
}
@Bean
public DirectExchange directExchange(){
return new DirectExchange("direct_exchange_springAMQP",false,true);
}
@Bean
public Queue queue003(){
return new Queue("queue003_name",true);
}
//将002队列绑定到topic交换机上
@Bean
public Binding binding3(){
return BindingBuilder.bind(queue003()).to(directExchange()).with("spring.send");
}
}
RabbitTemplate消息模板
RabbitTemplate类提供了丰富的发送消息方法,包括可靠性投递消息方法、回调监听消息接口ConfiremCallback、返回值确认接口ReturnCallback等等。同样,这个类我们也要注入到Spring容器中,然后才能使用。
config配置类
@Bean
public ConnectionFactory connectionFactory(){
CachingConnectionFactory factory=new CachingConnectionFactory();
factory.setAddresses("192.168.1.60:5672");
factory.setVirtualHost("/user_db");
factory.setUsername("users");
factory.setPassword("123");
return factory;
}
/**
* 注册rabbitTemplate消息模板
*/
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
return new RabbitTemplate(connectionFactory);
}
测试发送消息的方式
@SpringBootTest
public class RabbitTemplateTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMessage(){
/**
*利用convertAndSend可以简单发送消息
*/
rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.send2","稍微简单的发送一个消息".getBytes());
System.out.println("------------------------华丽的分割线---------------------------------");
/**
*rabbitTemplate.send的方式可以实现发送消息
*/
MessageProperties messageProperties2=new MessageProperties();
messageProperties2.getHeaders().put("type","消息类型");
Message message2=new Message("Hello RabbitMq".getBytes(),messageProperties2);
rabbitTemplate.send("topic_exchange_springAMQP","spring.send2",message2);
System.out.println("------------------------华丽的分割线---------------------------------");
/**
* 以下是对消息属性进行设置。然后在发送消息
*/
MessageProperties messageProperties=new MessageProperties();
messageProperties.getHeaders().put("desc","消息的描述。。。。");
messageProperties.getHeaders().put("type","消息类型");
// messageProperties.setExpiration("10000");//10秒不被消费,自动删除
//声明消息
Message message=new Message("Hello RabbitMq".getBytes(),messageProperties);
//设置发送到的交换机、路由key、消息、new MessagePostProcessor在发送之前,再对消息属性进行修改
rabbitTemplate.convertAndSend("topic_exchange_springAMQP", "spring.send", message, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
System.out.println("---------------消息发送之前,在对消息进行加工----------------------");
message.getMessageProperties().getHeaders().put("desc","修改了消息描述");
message.getMessageProperties().getHeaders().put("id","新增消息属性");
return message;
}
});
}
}
SimpleMessageListenerContainer简单消息监听容器
作用:
- 可以监听队列(多个队列)、自动启动、自动声明等功能。
- 也可以设置事务特性、事务管理器、事务属性、事务容量(并发)、是否开启事务、回滚消息等。
- 设置消息确认和自动确认模式、是否重回队列、异常捕获handler函数。
- 设置消费者标签生成策略、是否独占模式、消费者属性等。
- 设置具体的监听器、消息转换器等等。
注意:
- SimpleMessageListenerContainer可以进行动态设置。比如在运行中的应用可以动态修改其消费者的数量、接收消息的模式等。
/**
* 注册消息监听容器
* @param connectionFactory,将连接工厂当参数传过来。
* @return
*/
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
//注册SimpleMessageListenerContainer
SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
//设置需要监听队列
Container.setQueues(queue001(),queue002(),queue003());
//当前消费者数量
Container.setConcurrentConsumers(1);
//最大的消费者数量
Container.setMaxConcurrentConsumers(1);
//是否重回队列
Container.setDefaultRequeueRejected(false);
//设置消息签收模式(AUTO自动签收)
Container.setAcknowledgeMode(AcknowledgeMode.AUTO);
//是否自动声明
Container.setAutoDeclare(true);
//设置消费端消费标签策略
Container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue+"_"+ UUID.randomUUID().toString();
}
});
//设置消息监听。new一个消息监听器
Container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg=new String(message.getBody(),"UTF-8");
System.out.println("============消费者-----》"+msg);
}
});
//Container.set还有很多方法,适用很多地方。比如事务等等
return Container;
}
}
测试的话,请点击上面RabbitTemplate发送消息的测试类。点击发送,在控制台可以看到接收的消息。
MessageListenerAdapter消息监听适配器
在注册SimpleMessageListenerContainer 的时候,不用消息监听器的方法,自己创建一个消息监听适配器。将这个类。放入SimpleMessageListenerContainer监听容器中。
/**
* 注册消息监听容器
* @param connectionFactory
* @return
*/
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
//注册SimpleMessageListenerContainer
SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
/* //设置消息监听 ****这种方法不用了。
Container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg=new String(message.getBody(),"UTF-8");
System.out.println("============消费者-----》"+msg);
}
});*/
/**
* 第1种:用适配的方式,写一个消息监听适配器。
*/
MessageListenerAdapter messageListenerAdapter=new MessageListenerAdapter(new MyMessageListenerAdapter());
//设置指定方法
messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
Container.setMessageListener(messageListenerAdapter);
return Container;
}
自定义的消息适配器
public class MyMessageListenerAdapter {
/**
* 这个方法名字(handleMessage)是固定的,
* 如果配置类中没有指定默认方法,mq就会指定这个方法为默认方法。
* 如果指定其他方法,可以在配置类中使用messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
*/
public void handleMessage(byte[] messageBody) {
System.err.println("默认方法, 消息内容:" + new String(messageBody));
}
/**
* 覆盖默认的消息接收方法;
*/
public void consumeMessage(byte[] messageBody) {
System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
}
}
MessageListenerAdapter第二种方法:
queueOrTagToMethodName:将方法和队列进行绑定
/**
* 注册消息监听容器
* @param connectionFactory
* @return
*/
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
//注册SimpleMessageListenerContainer
SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
/* //设置消息监听 ****这种方法不用了。
Container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg=new String(message.getBody(),"UTF-8");
System.out.println("============消费者-----》"+msg);
}
});*/
/*//第1种:用适配的方式,写一个消息监听适配器。
MessageListenerAdapter messageListenerAdapter=new MessageListenerAdapter(new MyMessageListenerAdapter());
//设置指定方法
messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
Container.setMessageListener(messageListenerAdapter);*/
//第2种:我们可以将队列名称和方法名称进行一一对应
MessageListenerAdapter adapter =new MessageListenerAdapter(new MyMessageListenerAdapter());
Map<String,String> queueOrTagToMethodName=new HashMap<>();
//key是**队列名称,不是上面定义的bean的名称**,value是方法名称。方法定义在自己写的适配器中
queueOrTagToMethodName.put("queue003_name","method3");
queueOrTagToMethodName.put("queue002_name","method2");
adapter .setQueueOrTagToMethodName(queueOrTagToMethodName);
Container.setMessageListener(adapter);
return Container;
}
自定义的适配器,添加method2和method3两个方法
public class MyMessageListenerAdapter {
/**
* 这个方法名字(handleMessage)是固定的,
* 如果配置类中没有指定默认方法,mq就会指定这个方法为默认方法。
* 如果指定其他方法,可以在配置类中使用messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
*/
public void handleMessage(byte[] messageBody) {
System.err.println("默认方法, 消息内容:" + new String(messageBody));
}
/**
* 覆盖默认的消息接收方法;
*/
public void consumeMessage(byte[] messageBody) {
System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
}
public void method3(byte[] messageBody) {
System.err.println("方法3,绑定在队列3上-------:" + new String(messageBody));
}
public void method2(byte[] messageBody) {
System.err.println("方法2,绑定在队列2上-------:" + new String(messageBody));
}
}
测试类
@Test
public void testmessage2(){
rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.save","应该是发送到方法2上".getBytes());
rabbitTemplate.convertAndSend("direct_exchange_springAMQP","direct.save","发送到方法3上".getBytes());
}
MessageConverter消息转换器
解析:我们在发送消息的时候,正常情况下消息体为二进制的数据方法(getBytes),如果我们内部需要转换,或者指定自定义转换器,就需要用到MessageConverter。
将字节转换成字符串
1.自定义转换器类
/**
* 自定义转换器类,实现MessageConverter接口,重写tomessage和frommessage两个方法。将字节转换成字符串。
*/
public class TextMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(object.toString().getBytes(), messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
return new String(message.getBody());
}
}
2.config类
/**
* 注册消息监听容器
* @param connectionFactory
* @return
*/
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
//注册SimpleMessageListenerContainer
SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
/**
* 1 适配器方式. 默认是有自己的方法名字的:handleMessage
*/
MessageListenerAdapter adapter = new MessageListenerAdapter(new MyMessageListenerAdapter());
//下面的consumeMessage方法,就可以直接用string接收
adapter.setDefaultListenerMethod("consumeString");
//set设置消息转换器,接收的消息就不在是字节数据,可以是字符串直接输出
adapter.setMessageConverter(new TextMessageConverter());
Container.setMessageListener(adapter);
return Container;
}
3.在自定义消息监听器类中,定义接收方法
public class MyMessageListenerAdapter {
public void handleMessage(byte[] messageBody) {
System.err.println("默认方法, 消息内容:" + new String(messageBody));
}
public void consumeMessage(byte[] messageBody) {
System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
}
/**
*以上方法的接收都是字节。
* 消息转换器,将字节转成字符串。
*/
public void consumeString(String messageBody) {
System.err.println("测试字节转换成字符串:" + messageBody);
}
}
4.定义测试方法。
@Test
public void testSendMessageSting(){
rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.send","测试消息转换成string".getBytes());
}
支持json转换器
1.config类
/**
* 注册消息监听容器
* @param connectionFactory
* @return
*/
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
//注册SimpleMessageListenerContainer
SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
/**
* 定义支持json格式的转换器
*/
MessageListenerAdapter adapter = new MessageListenerAdapter(new MyMessageListenerAdapter());
//接收的方法,参数必须是map格式
adapter.setDefaultListenerMethod("consumeJson");
//new 一个Jackson2JsonMessageConverter,并将这个类,set到消息监听器中
Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
adapter.setMessageConverter(jackson2JsonMessageConverter);
Container.setMessageListener(adapter);
return Container;
}
2.在自定义消息监听器类中,定义接收方法。接收参数必须是map
public class MyMessageListenerAdapter {
public void handleMessage(byte[] messageBody) {
System.err.println("默认方法, 消息内容:" + new String(messageBody));
}
public void consumeMessage(byte[] messageBody) {
System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
}
public void consumeString(String messageBody) {
System.err.println("测试字节转换成字符串:" + messageBody);
}
/**
* 定义接收json格式数据
* @param messageBody
*/
public void consumeJson(Map messageBody) {
System.err.println("测试字节转换成json格式:" + messageBody);
}
}
3.定义测试方法
@Test
public void testSendMessageJson() throws JSONException {
JSONObject jsonObject=new JSONObject();
jsonObject.put("desc","111");
jsonObject.put("id","32");
rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.send",jsonObject.toString().getBytes());
}