RabbitMQ-Spring整合

目錄

Spring-boot中通過註解封裝RabbitMQ的使用。

Spring通過XML配置使用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。

  1. 通過Maven加入Spring與RabbitMQ的依賴。
    <!--rabbitmq依賴 -->  
    <dependency>  
        <groupId>org.springframework.amqp</groupId>  
        <artifactId>spring-rabbit</artifactId>  
        <version>1.3.5.RELEASE</version>  
    </dependency>  
  2. 通過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>
  1. 實現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);
    	}
    }

     

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章