RabbitMQ与 springboot2.x 整合

springboot 集成 rabbitmq 非常方便,只需引入一个依赖包,交换机队列等都可以直接通过注释完成。

我新建了两个项目,pom 文件是一样的,如下:

		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-amqpartifactId>
		dependency>
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-webartifactId>
		dependency>

		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-actuatorartifactId>
		dependency>

我一开始没有引入 web 依赖,但是用测试用例的时候,我执行测试方法时,报错说连接已经关闭了。因此,我是启动了整个项目,写了 controller 测试成功。

生产者

配置文件 application.properties

spring.rabbitmq.addresses=192.168.0.125
spring.rabbitmq.virtual-host=/
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

spring.rabbitmq.publisher-returns=true
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.template.mandatory=true

需一个配置类,现在没写什么配置,但是得加上扫描注解

@Configuration
@ComponentScan({"com.xiao.*"})
public class MainConfig {

}

消息发送类

import java.util.Map;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import com.xiao.entity.LetterBody;

@Component
public class SendMessage {

	@Autowired
	private RabbitTemplate rabbitTemplate;
	
	// 回调方法--确认机制
	final ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
		@Override
		public void confirm(CorrelationData correlationData, boolean ack, String cause) {
			System.out.println("correlationData==" + correlationData);
			System.out.println("ack==" + ack);
			System.out.println(cause);
			if(!ack) {
				System.out.println("ack 失败!请重新操作。。。。");
			}
			
		}
	};
	
	// 回调方法--return 机制
	final ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
		@Override
		public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText,
				String exchange, String routingKey) {
			
			System.out.println("returnCallback: exchange==" + exchange + ", routingKey==" + routingKey 
					+ ", replyCode==" + replyCode + ", replyText=="+ replyText);
			
		}
	};
	
	// 发送 Object 消息对象
	public void send(Object message, Map<String, Object> properties) {
		MessageHeaders headers = new MessageHeaders(properties);
		Message msg = MessageBuilder.createMessage(message, headers);
		rabbitTemplate.setConfirmCallback(confirmCallback);
		rabbitTemplate.setReturnCallback(returnCallback);
		CorrelationData correlationData = new CorrelationData();
		correlationData.setId("123asdfg321"); // 须全局唯一,为消息的实际id
		rabbitTemplate.convertAndSend("exchange-boot", "boot.test", msg, correlationData);// 预先创建好的交换机和队列
	}
	
	//发送 java 类对象
	public void sendLetter(LetterBody letter) {
		rabbitTemplate.setConfirmCallback(confirmCallback);
		rabbitTemplate.setReturnCallback(returnCallback);
		CorrelationData correlationData = new CorrelationData();
		correlationData.setId("1234asdfg4321"); // 须全局唯一
		rabbitTemplate.convertAndSend("exchange-boot", "boot.test", letter, correlationData);// 预先创建好的交换机和队列
	}
	
}

消息发送类中第二种消息类型是一个自定义 java 对象,须自定义一个实体对象,并实现序列化

public class LetterBody implements Serializable {

	private String lid;
	private String lcontent;
	
	public LetterBody() {
	}
	
	public LetterBody(String lid, String lcontent) {
		super();
		this.lid = lid;
		this.lcontent = lcontent;
	}
	
	public String getLid() {
		return lid;
	}
	public void setLid(String lid) {
		this.lid = lid;
	}
	public String getLcontent() {
		return lcontent;
	}
	public void setLcontent(String lcontent) {
		this.lcontent = lcontent;
	}
	
}

测试类 or 控制类

@RestController
public class SendController {

	@Autowired
	private SendMessage sendMessage;
	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	@RequestMapping("/send")
	public String testSendMessage() {
		HashMap<String, Object> properties = new HashMap<>();
		properties.put("mid", "123456789");
		properties.put("createTime", sdf.format(new Date()));
		sendMessage.send("boot send message!!", properties);
		return "over";
	}
	
	@RequestMapping("/sendObj")
	public String testSendLetter() {
		LetterBody letterBody = new LetterBody("toremote001","给远方的一封信");
		sendMessage.sendLetter(letterBody);
		return "over";
	}
}

写成测试类只要改相应的注解即可

执行测试方法 or 主入口类,如下图
RabbitMQ与 springboot2.x 整合_第1张图片下图是执行测试方法,在ack之前,连接关闭了,导致 ack 失败
RabbitMQ与 springboot2.x 整合_第2张图片下图是启动了项目,ack 成功
RabbitMQ与 springboot2.x 整合_第3张图片把交换机名称或队列名称或路由键改成不存在的,即可看到回调了 return 方法
RabbitMQ与 springboot2.x 整合_第4张图片

消费者

配置文件 application.properties

spring.rabbitmq.addresses=192.168.0.125
spring.rabbitmq.virtual-host=/
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.connection-timeout=30000

spring.rabbitmq.listener.simple.acknowledge-mode=manual
spring.rabbitmq.listener.simple.concurrency=5
spring.rabbitmq.listener.simple.max-concurrency=15


spring.rabbitmq.listener.letterBody.queue.name=queue-boot
spring.rabbitmq.listener.letterBody.queue.durable=true
spring.rabbitmq.listener.letterBody.exchange.name=exchange-boot
spring.rabbitmq.listener.letterBody.exchange.durable=true
spring.rabbitmq.listener.letterBody.exchange.type=topic
spring.rabbitmq.listener.letterBody.exchange.ignoreDeclarationExceptions=true
spring.rabbitmq.listener.letterBody.key=boot.#

同样需要一个配置类,加上扫描包,同上。

接下来是消息接收类

import java.util.Map;

import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import com.rabbitmq.client.Channel;
import com.xiao.entity.LetterBody;

@Component
public class ReceiveMessage {

	//以下队列和交换机如果不存在,会自动创建
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = "queue-boot", durable = "true"),
			exchange = @Exchange(value = "exchange-boot", type = "topic", 
			durable = "true", ignoreDeclarationExceptions = "true"),
			key = "boot.#"
			)
	)
	@RabbitHandler
	public void onMessage(Message message, Channel channel) throws Exception {
		System.out.println("---------------Message---------------");
		System.out.println("consumer payload===" + message.getPayload());
		Long deliveryTag = (Long)message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
		// 手工 ack
		channel.basicAck(deliveryTag, false);
	}
	
	/**
	 * 	spring.rabbitmq.listener.letterBody.queue.name=queue-boot
		spring.rabbitmq.listener.letterBody.queue.durable=true
		spring.rabbitmq.listener.letterBody.exchange.name=exchange-boot
		spring.rabbitmq.listener.letterBody.exchange.durable=true
		spring.rabbitmq.listener.letterBody.exchange.type=topic
		spring.rabbitmq.listener.letterBody.exchange.ignoreDeclarationExceptions=true
		spring.rabbitmq.listener.letterBody.key=boot.#
	 * @param letter
	 * @param channel
	 * @param heads
	 * @throws Exception
	 */
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = "${spring.rabbitmq.listener.letterBody.queue.name}", 
				durable = "${spring.rabbitmq.listener.letterBody.queue.durable}"),
			exchange = @Exchange(value = "${spring.rabbitmq.listener.letterBody.exchange.name}", 
				type = "${spring.rabbitmq.listener.letterBody.exchange.type}", 
				durable = "${spring.rabbitmq.listener.letterBody.exchange.durable}", 
				ignoreDeclarationExceptions = "${spring.rabbitmq.listener.letterBody.exchange.ignoreDeclarationExceptions}"),
				key = "${spring.rabbitmq.listener.letterBody.key}")
			)
	@RabbitHandler
	public void onLetterMessage(@Payload LetterBody letter, Channel channel, 
			@Headers Map<String, Object> heads ) throws Exception {
		System.out.println("---------------Letter Message---------------");
		System.out.println("consumer Letter Message===" + letter.getLid() + "-->" + letter.getLcontent());
		Long deliveryTag = (Long)heads.get(AmqpHeaders.DELIVERY_TAG);
		// 手工 ack
		channel.basicAck(deliveryTag, false);
	}
	
}

测试发送的 java 对象消息,同样需要实体类,同上

最后就是测试了
执行主入口类,启动项目就能看的消息被接收了,如图
RabbitMQ与 springboot2.x 整合_第5张图片

你可能感兴趣的:(springboot,RabbitMQ)