目录
Spring-boot中通过注解封装RabbitMQ的使用。
通过前面的RabbitMQ的java应用,我们初步了解到MQ的使用。在实际中,我们基本上都不需要这么用,可以直接通过把rabbitMQ整合Spring中,spring帮我们封装了一些消息者、生产者的功能,我们可以直接使用。
Spring-boot中通过注解封装RabbitMQ的使用。
1.添加依赖pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.配置服务器、用户、密码application.properties
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5673
spring.rabbitmq.username=root
spring.rabbitmq.password=root
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
3.通过注解定义队列、交换器等。
package mytest.springboot.myRabbitMQTest.common;
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import mytest.springboot.myRabbitMQTest.common.producer.MyConfirmCallback;
import mytest.springboot.myRabbitMQTest.common.producer.MyReturnCallBack;
/**
* RabbitMQ 配置
*/
@Configuration
public class RabbitMQConfig {
@Bean
RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
@Bean
Queue queueFooDead(RabbitAdmin rabbitAdmin) {
Queue queue = new Queue("queue.fooErr", true,true, false);
rabbitAdmin.declareQueue(queue);
return queue;
}
@Bean
FanoutExchange deadExchange(RabbitAdmin rabbitAdmin) {
FanoutExchange deadExchange = new FanoutExchange("deadExchange");
rabbitAdmin.declareExchange(deadExchange);
return deadExchange;
}
@Bean
Binding bindingExchangeFooDead(Queue queueFooDead, FanoutExchange deadExchange, RabbitAdmin rabbitAdmin) {
Binding binding = BindingBuilder.bind(queueFooDead).to(deadExchange);
rabbitAdmin.declareBinding(binding);
return binding;
}
@Bean
Queue queueFoo(RabbitAdmin rabbitAdmin) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-dead-letter-exchange", "deadExchange");// 设置死信交换机
map.put("x-dead-letter-routing-key", "mail_queue_fail");// 设置死信routingKey
Queue queue = new Queue("queue.foo", true, false, false, map);
rabbitAdmin.declareQueue(queue);
return queue;
}
@Bean
Queue queueBar(RabbitAdmin rabbitAdmin) {
Queue queue = new Queue("queue.bar", true);
rabbitAdmin.declareQueue(queue);
return queue;
}
@Bean
TopicExchange exchange(RabbitAdmin rabbitAdmin) {
TopicExchange topicExchange = new TopicExchange("exchange");
rabbitAdmin.declareExchange(topicExchange);
return topicExchange;
}
@Bean
Binding bindingExchangeFoo(Queue queueFoo, TopicExchange exchange, RabbitAdmin rabbitAdmin) {
Binding binding = BindingBuilder.bind(queueFoo).to(exchange).with("queue.foo");
rabbitAdmin.declareBinding(binding);
return binding;
}
@Bean
Binding bindingExchangeBar(Queue queueBar, TopicExchange exchange, RabbitAdmin rabbitAdmin) {
Binding binding = BindingBuilder.bind(queueBar).to(exchange).with("queue.bar");
rabbitAdmin.declareBinding(binding);
return binding;
}
/**
* 生产者用
*
* @return
*/
@Bean
public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
RabbitMessagingTemplate rabbitMessagingTemplate = new RabbitMessagingTemplate();
rabbitMessagingTemplate.setMessageConverter(jackson2Converter());
rabbitMessagingTemplate.setRabbitTemplate(rabbitTemplate);
// 消息发送失败返回到队列中, yml需要配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
// 消息返回, yml需要配置 publisher-returns: true
rabbitTemplate.setReturnCallback(new MyReturnCallBack()); // 消息最终没有进行队列时回调
// 消息确认, yml需要配置 publisher-confirms: true
rabbitTemplate.setConfirmCallback(new MyConfirmCallback());// 消息保存成功后回调
return rabbitMessagingTemplate;
}
@Bean
public MappingJackson2MessageConverter jackson2Converter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
return converter;
}
}
package mytest.springboot.myRabbitMQTest.common.consumer;
import java.io.IOException;
import java.util.Random;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import mytest.springboot.myRabbitMQTest.Vo.Bar;
import mytest.springboot.myRabbitMQTest.Vo.Foo;
import com.rabbitmq.client.Channel;
@Component
public class ReceiverService {
//消费者
@RabbitListener(queues = "queue.bar")
public void receiveBarQueue(Bar bar) {
System.out.println("Received Bar<" + bar.getAge() + ">");
}
}
生产者
package mytest.springboot.myRabbitMQTest.common.producer;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import mytest.springboot.myRabbitMQTest.Vo.Bar;
import mytest.springboot.myRabbitMQTest.Vo.Foo;
@Component
public class SenderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendFoo2RabbitmqByRabbitTemplate(final Foo foo) {
System.out.println("发送成功开始");
CorrelationData correlationData = new CorrelationData();
correlationData.setId("12345678911111111111");
this.rabbitTemplate.convertAndSend("exchange", "queue.foo", foo ,correlationData);
System.out.println("发送成功完成1");
CorrelationData correlationData2 = new CorrelationData();
correlationData2.setId("12345678911111111112");
this.rabbitTemplate.convertAndSend("exchange", "queue.foo", foo ,correlationData2);//异步方法
System.out.println("发送成功完毕");
}
}
Spring通过XML配置使用rabbitMQ。
- 通过Maven加入Spring与RabbitMQ的依赖。
<!--rabbitmq依赖 --> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> <version>1.3.5.RELEASE</version> </dependency>
- 通过Spring配置rabbit:connection-factory、rabbit:admin、队列、rabbit:template消息模板、交换器(绑定的队列)、消费端、生产端。
以下是XML方式配置
<!-- 消费端配置 ********************************************** -->
<!--配置connection-factory,指定连接rabbit server参数 -->
<rabbit:connection-factory id="connectionFactory" virtual-host="/" username="${rabbitmq.user}" password="${rabbitmq.password}"
host="${rabbitmq.ip}" port="${rabbitmq.port}" />
<!-- username="root" password="root" host="127.0.0.1" -->
<!--通过指定下面的admin信息,当前producer中的exchange和queue会在rabbitmq服务器上自动生成 -->
<rabbit:admin id="connectAdmin" connection-factory="connectionFactory" />
<!--定义queue -->
<rabbit:queue name="queue1" durable="true" auto-delete="false" exclusive="false" declared-by="connectAdmin" />
<!-- 定义direct exchange,绑定queue1 -->
<rabbit:direct-exchange name="exchange1"
durable="true" auto-delete="false" declared-by="connectAdmin">
<rabbit:bindings>
<rabbit:binding queue="queue1" key="keys"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<!--定义rabbit template用于数据的接收和发送 -->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" exchange="exchange1" />
<!-- 消息接收者 (消费者) ,自动确认-->
<bean id="messageReceiver" class="test.rabbitmq.MessageConsumer"></bean>
<!-- 消息接收者 (消费者),需要手功确认 -->
<bean id="ackMessageReceiver" class="test.rabbitmq.AckMessageConsumer"></bean>
<!-- queue litener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象 -->
<rabbit:listener-container connection-factory="connectionFactory" >
<rabbit:listener queues="queue1" ref="messageReceiver" />
</rabbit:listener-container>
<!--<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="manual">
<rabbit:listener queues="queue1" ref="ackMessageReceiver" />
</rabbit:listener-container> -->
<!-- 消费端配置 end*************** ******************* -->
<!-- 生产端 , 不需要确认-->
<rabbit:template id="amqpSendTemplate" connection-factory="connectionSendFactory" exchange="exchange1" />
<bean id="messageProducer" class="test.rabbitmq.MessageProducer">
<property name="amqpTemplate">
<ref bean="amqpSendTemplate" />
</property>
</bean>
<!-- 生产端 ,带确认-->
<rabbit:template id="amqpSendTemplateRabbit" connection-factory="connectionSendFactory" exchange="exchange1"
confirm-callback="confirmCallBackListener" return-callback="returnCallBackListener" mandatory="true" />
<bean id="messageProducerAck" class="test.rabbitmq.MessageRabbitProducer">
<property name="amqpTemplate">
<ref bean="amqpSendTemplateRabbit" />
</property>
</bean>
<bean id="confirmCallBackListener"
class="test.rabbitmq.ConfirmCallBack">
</bean>
<bean id="returnCallBackListener"
class="test.rabbitmq.ReturnCallBack">
</bean>
- 实现MessageListener接口的MessageConsumer类跟实现ChannelAwareMessageListener(支持手动应答)类 AckMessageConsumer 进行队列消费的消费。
package test.rabbitmq; import java.io.UnsupportedEncodingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageListener; public class MessageConsumer implements MessageListener { private Logger logger = LoggerFactory.getLogger(MessageConsumer.class); @Override public void onMessage(Message message) { logger.info("consumer receive message------->:{}", message); String message1; try { message1 = new String(message.getBody(), "UTF-8"); logger.info("consumer receive message------->:{}",message1 ); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package com.sinosig.sgis.cls.common.rabbitmq; import java.io.UnsupportedEncodingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener; import com.rabbitmq.client.Channel; public class AckMessageConsumer implements ChannelAwareMessageListener{ private Logger logger = LoggerFactory.getLogger(MessageConsumer.class); @Override public void onMessage(Message message, Channel arg1) throws Exception { logger.info("ACK consumer receive message------->:{}", message); String message1; try { message1 = new String(message.getBody(), "UTF-8"); logger.info("ACK consumer receive message------->:{}",message1 ); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread.sleep(10000); logger.info("ACK END"); //消费确认 arg1.basicAck(message.getMessageProperties().getDeliveryTag(), true); //消费拒绝 // logger.info("ACK REJECT"); // arg1.basicReject(message.getMessageProperties().getDeliveryTag(), true); //第二个参数表示放回原消息队列 } }
2.配置rabbit:template模板,配置AmqpTemplate 进行消息的生产,配置实现ConfirmCallback接口进行消息发送的确认。
package test.rabbitmq; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.AmqpTemplate; public class MessageProducer { private Logger logger = LoggerFactory.getLogger(MessageProducer.class); private AmqpTemplate amqpTemplate; public AmqpTemplate getAmqpTemplate() { return amqpTemplate; } public void setAmqpTemplate(AmqpTemplate amqpTemplate) { this.amqpTemplate = amqpTemplate; } public void sendMessage(Object message) throws IOException { logger.info("to send message:{}", message); //u普通生产消息 amqpTemplate.convertAndSend("keys", message); } }
package test.rabbitmq; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.AmqpTemplate; public class MessageRabbitProducer { private Logger logger = LoggerFactory.getLogger(MessageProducer.class); private AmqpTemplate amqpTemplate; public AmqpTemplate getAmqpTemplate() { return amqpTemplate; } public void setAmqpTemplate(AmqpTemplate amqpTemplate) { this.amqpTemplate = amqpTemplate; } public void sendMessage(Object message) throws IOException { logger.info("to send message:{}", message); amqpTemplate.convertAndSend("keys", message); amqpTemplate.convertAndSend("keys1111", message); } }
package test.rabbitmq; import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback; import org.springframework.amqp.rabbit.support.CorrelationData; public class ConfirmCallBack implements ConfirmCallback { @Override public void confirm(CorrelationData correlationData, boolean ack) { System.out.println("confirm--:correlationData:" + correlationData + ",ack:" + ack + ",cause:" ); } }
package test.rabbitmq; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback; public class ReturnCallBack implements ReturnCallback { @Override public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { System.out.println("return--message:" + new String(message.getBody()) + ",replyCode:" + replyCode + ",replyText:" + replyText + ",exchange:" + exchange + ",routingKey:" + routingKey); } }