RabbitMQ与 springboot2.x 整合

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

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</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 主入口类,如下图
在这里插入图片描述下图是执行测试方法,在ack之前,连接关闭了,导致 ack 失败
在这里插入图片描述下图是启动了项目,ack 成功
在这里插入图片描述把交换机名称或队列名称或路由键改成不存在的,即可看到回调了 return 方法
在这里插入图片描述

消费者

配置文件 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 对象消息,同样需要实体类,同上

最后就是测试了
执行主入口类,启动项目就能看的消息被接收了,如图
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Alias_fa/article/details/102636038