rabbitMq实例讲解,以springboot为主
一生产者
1.引包
<dependencies>
<!-- fast json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.配置文件
spring:
rabbitmq:
producer:
addresses: 127.0.0.1:5672
userName: developer
password: dev0423
publisher-confirms: true --发布者确认
virtual-host: dev
3.RabbitMq配置文件读取类
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq.consumer")
public class RabbitMqConfig {
@Value("${spring.rabbitmq.consumer.addresses}")
private String addresses;
@Value("${spring.rabbitmq.consumer.userName}")
private String username;
@Value("${spring.rabbitmq.consumer.password}")
private String password;
@Value("${spring.rabbitmq.consumer.publisher-confirms}")
private Boolean publisherConfirms;
@Value("${spring.rabbitmq.consumer.virtual-host}")
private String virtualHost;
// 构建mq实例工厂
@Bean
public ConnectionFactory connectionFactory(){
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses(addresses);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setPublisherConfirms(publisherConfirms);
connectionFactory.setVirtualHost(virtualHost);
return connectionFactory;
}
/**
*rabbitMq代理类
*该类封装了对 RabbitMQ 的管理操作
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
return new RabbitAdmin(connectionFactory);
}
/**
* 创建rabbitTemplate 消息模板类
* prototype原型模式:每次获取Bean的时候会有一个新的实例
* 因为要设置回调类,所以应是prototype类型,如果是singleton类型,则回调类为最后一次设置
* @return
*/
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate rabbitTemplate(){
RabbitTemplate template = new RabbitTemplate(connectionFactory());
// rabbitTemplate.setMandatory(true);//返回消息必须设置为true
template.setMessageConverter(jackson2JsonMessageConverter());数据转换为json
存入消息队列
//发布确认
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
//消息发送到queue时就执行
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
log.debug(correlationData+"//");
if (!b){
log.debug("发送到queue失败");
throw new RuntimeException("send error " + s);
}
}
});
return template;
}
@Bean
public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
3.rabbitMq发送工具类
生产者想要发送消息,首先必须要声明一个Exchange和该Exchange对应的Binding
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
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;
@Component
public class RabbitMqSender implements RabbitTemplate.ConfirmCallback{
/** logger */
private static final Logger logger = LoggerFactory.getLogger(RabbitMqSender.class);
private RabbitTemplate rabbitTemplate;
@Autowired
public RabbitMqSender(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
this.rabbitTemplate.setConfirmCallback(this);
}
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
logger.info("confirm: " + correlationData.getId());
}
/**
* 发送到 指定routekey的指定queue
* @param routeKey
* @param obj
*/
public void sendRabbitmqDirect(String exchange, String routeKey, String queueName, Object obj) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
logger.info("send: " + correlationData.getId());
this.rabbitTemplate.setExchange(exchange);//动态绑定
this.rabbitTemplate.setRoutingKey(routeKey);
RabbitAdmin admin = new RabbitAdmin(this.rabbitTemplate.getConnectionFactory());
admin.declareQueue(new Queue(queueName));//声明队列
DirectExchange directExchange = new DirectExchange(exchange);
admin.declareExchange(directExchange);//声明交换机
Binding binding = BindingBuilder.bind(new Queue(queueName)).to(directExchange).with(routeKey);//进行绑定
admin.declareBinding(binding);
this.rabbitTemplate.convertAndSend(exchange, routeKey , obj, correlationData);
}
/**
* 所有发送到Topic Exchange的消息被转发到所有关心RouteKey中指定Topic的Queue上
* @param routeKey
* @param obj
*/
public void sendRabbitmqTopic(String exchange, String routeKey, String queueName, Object obj) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
logger.info("send: " + correlationData.getId());
this.rabbitTemplate.setExchange(exchange);
this.rabbitTemplate.setRoutingKey(routeKey);
RabbitAdmin admin = new RabbitAdmin(this.rabbitTemplate.getConnectionFactory());
admin.declareQueue(new Queue(queueName));
TopicExchange topicExchange = new TopicExchange(exchange);
admin.declareExchange(topicExchange);
Binding binding = BindingBuilder.bind(new Queue(queueName)).to(topicExchange).with(routeKey);
admin.declareBinding(binding);
this.rabbitTemplate.convertAndSend(exchange, routeKey , obj, correlationData);
}
}
4.测试发送
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration
public class TestSendMsg {
@Autowired
private RabbitMqSender rabbitMqSender;
@Test
public void test() {
boolean isTopic = true;
if (!isTopic) {
//direct测试
TUserTest user = new TUserTest("1","123456 sending message");
rabbitMqSender.sendRabbitmqDirect("exchangeD","routingkeyD","queneD", user);
} else {
TUserTest user = new TUserTest("2","123456 sending topic message");
rabbitMqSender.sendRabbitmqTopic("exchangeT","routingkeyT","queneT", user);
}
//rabbitMqSender.sendRabbitmqTopic("exchangeT","routingkeyT", user);
rabbitMqSender.sendRabbitmqDirect("TESTQUEUE1", "1");
rabbitMqSender.sendRabbitmqTopic("*.TEST.*", "2");
rabbitMqSender.sendRabbitmqTopic("lazy.#","3");
}
}
二.消费者
1.导包,与生产者一样
2.配置文件
spring:
rabbitmq:
consumer:
addresses: 127.0.0.1:5672
userName: developer
password: dev0423
publisher-confirms: true --发布者确认
virtual-host: dev
3.消费者配置
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq.consumer")
public class RabbitMqConsumerConfig {
@Value("${spring.rabbitmq.consumer.addresses}")
private String addresses;
@Value("${spring.rabbitmq.consumer.userName}")
private String username;
@Value("${spring.rabbitmq.consumer.password}")
private String password;
@Value("${spring.rabbitmq.consumer.publisher-confirms}")
private Boolean publisherConfirms;
@Value("${spring.rabbitmq.consumer.virtual-host}")
private String virtualHost;
// 构建mq实例工厂,bean指定name为了防止和mq producer的冲突,下同
@Bean(name="consumerConnectionFactory")
public ConnectionFactory connectionFactory(){
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses(addresses);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setPublisherConfirms(publisherConfirms);
connectionFactory.setVirtualHost(virtualHost);
return connectionFactory;
}
@Bean(name="consumerRabbitAdmin")
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
return new RabbitAdmin(connectionFactory);
}
@Bean(name="consumerRabbitTemplate")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate rabbitTemplate(){
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setMessageConverter(jackson2JsonMessageConverter());
return template;
}
@Bean(name="consumerJackson2JsonMessageConverter")
public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
4.配置消费者监听
1)直联
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.fastjson.JSON;
import com.qihai.commerce.framework.mq.consumer.RabbitMqConfig;
import com.rabbitmq.client.Channel;
/**
* 直连消费者配置
*
* @author zhugj
* @date 2018年5月24日 下午2:03:29
* @version 1.0.0
*/
@Configuration
@AutoConfigureAfter(RabbitMqConfig.class)
public class DirectAmqpConfiguration {
@Bean("testQueueContainer")
public MessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("queneD");
container.setMessageListener(listener());
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);设置确认模式手工确认,
设置为手动,默认为 AUTO,如果设置了手动应答 basicack,就要设置manual
return container;
}
@Bean("testQueueListener")
public ChannelAwareMessageListener listener() {
return new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String str = new String(message.getBody());
TUserTest userTest = null;
try {
userTest = JSON.parseObject(str, TUserTest.class);
} catch (Exception e) {
e.printStackTrace();
}
//通过设置TestUser的name来测试回调,分别发两条消息,一条UserName为1,一条为2,查看控制台中队列中消息是否被消费
if ("1".equals(userTest.getId())){
System.err.println("我已经消费1成功了");
//手动确认。消息的标识,false只确认当前一个消息收到,true确认所有consumer获得的消息 (正常消费) channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
if ("2".equals(str)){
System.err.println("消息重新回到队列");
//ack返回false,并重新回到队列,api里面解释得很清楚 (本地异常) channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
}
}
};
}
}
2) topicjia监听类
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.fastjson.JSON;
import com.qihai.commerce.framework.mq.consumer.RabbitMqConfig;
import com.rabbitmq.client.Channel;
/**
* topic消费者配置
*
* @author zhugj
* @date 2018年5月24日 下午2:03:29
* @version 1.0.0
*/
@Configuration
@AutoConfigureAfter(RabbitMqConfig.class)
public class TopicAmqpConfiguration {
@Bean("topicTest1Container")
public MessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("queneT");
container.setMessageListener(listener1());
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return container;
}
@Bean("topicTest1Listener")
public ChannelAwareMessageListener listener1(){
return new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String str = new String(message.getBody());
TUserTest userTest = null;
try {
userTest = JSON.parseObject(str, TUserTest.class);
} catch (Exception e) {
e.printStackTrace();
}
if ("2".equals(userTest.getId())) {
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
System.err.println("我已经消费2成功了");
} else if ("3".equals(userTest.getId())) { //如果有异常决定是否保留消息在队列中,basicNack是保留消息在队列中
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
System.err.println("消息重新回到队列");
}
}
};
}
}
参考文章:
RabbitMq写的比较好的:https://www.cnblogs.com/vipstone/p/9275256.html
Springboot+rabbotMq的:https://blog.csdn.net/ztx114/article/details/78410727