Messaging middleware --RabbitMQ (ten) RabbitMQ integration SpringBoot combat! (all)

Seeking attention
RabbitMQ integration SpringBoot combat!  (all)

Foreword

1. SpringBoot integration configuration in detail

  • publisher-confirms, to achieve a listener listens for a confirmation request to the Broker end we return to:RabbitTemplate.ConfirmCallback

  • publisher-returns, to ensure end Broker message is reachable, if the routing key appears unreachable, then use the Listener unreachable message for subsequent processing, message routing to ensure success:RabbitTemplate.ReturnCallback

Note that, for the configuration template mandatory when sending a message to listen to ensure efficient production = true end may also configure other properties, such as transmission retry, timeout, number, interval, etc.

2. The code demonstrates

2.1 Production end

2.1.1 New Project springboot-producer

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.cp</groupId>
	<artifactId>springboot-producer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>springboot-producer</name>
	<description>springboot-producer</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>


复制代码

RabbitSender.java news producer


@Component
public class RabbitSender {

	//自动注入RabbitTemplate模板类
	@Autowired
	private RabbitTemplate rabbitTemplate;  
	
	//回调函数: confirm确认
	final ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
		@Override
		public void confirm(CorrelationData correlationData, boolean ack, String cause) {
			System.err.println("correlationData: " + correlationData);
			System.err.println("ack: " + ack);
			if(!ack){
				//可以进行日志记录、异常处理、补偿处理等
				System.err.println("异常处理....");
			}else {
				//更新数据库,可靠性投递机制
			}
		}
	};
	
	//回调函数: 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.err.println("return exchange: " + exchange + ", routingKey: " 
				+ routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
		}
	};
	
	//发送消息方法调用: 构建Message消息
	public void send(Object message, Map<String, Object> properties) throws Exception {
		MessageHeaders mhs = new MessageHeaders(properties);
		Message msg = MessageBuilder.createMessage(message, mhs);
		rabbitTemplate.setConfirmCallback(confirmCallback);
		rabbitTemplate.setReturnCallback(returnCallback);
		//id + 时间戳 全局唯一  用于ack保证唯一一条消息,这边做测试写死一个。但是在做补偿策略的时候,必须保证这是全局唯一的消息
		CorrelationData correlationData = new CorrelationData("1234567890");
		rabbitTemplate.convertAndSend("exchange-1", "springboot.abc", msg, correlationData);
	}
	
}


复制代码

application.properties


spring.rabbitmq.addresses=localhost:5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/vhost_cp
spring.rabbitmq.connection-timeout=15000

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

复制代码

2.1.2 Operation control station

Add Exchange

Exchange-1
Added successfully

Add Queue

Queue-1

Binding Exchange Queue

Binding
Binding success

Modify routingKey, springboot changed to spring, then enter the method is returnCallback

returnCallback print log - error

This time we found the error

correlationData: CorrelationData [id=1234567890]
ack: false
异常处理....

复制代码

returnCallback print log - correct

Ack to solve the problem of false 2.1.3

This is because we tested in the test method, when the end of the test method, rabbitmq related resources also closed, although our message out, but asynchronous ConfirmCallback was closed due to resource and the emergence of the above problems. Join Thread.sleep () can be solved.


@Test
public void testSender1() throws Exception {
	 Map<String, Object> properties = new HashMap<>();
	 properties.put("number", "12345");
	 properties.put("send_time", simpleDateFormat.format(new Date()));
	 rabbitSender.send("Hello RabbitMQ For Spring Boot!", properties);
	 Thread.sleep(2000);
}

复制代码

2.2 Consumer end

Core consumer side configuration:

Sign ## mode - manual sign spring.rabbitmq.listener.simple.acknowledge-mode = manual ## is provided to limit monitor: maximum 10, default 5 spring.rabbitmq.listener.simple.concurrency = 5 spring.rabbitmq.listener.simple. max-concurrency = 10

  • Manually configured first acknowledgment mode, the ACK for manual processing, so that we can guarantee the reliability of message delivery, then the consumer or the end can be done when the consumer fails to return queue (not recommended), according to process traffic logs like.

  • You can set the maximum number of the number of listeners and the consumer side, for concurrent monitoring of the consumer side of the case

@RabbitListener use annotations

  • Consumer end monitor @RabbitListener notes, in practical work for this very easy to use
  • @RabbitListener annotation is a combination, which can be configured annotations
  • @ QueueBinding, @ Queue, @ Exchange directly through this combination of notes to get a one-time consumer side switches, queue, binding, routing, and configuration monitoring function and so on.

@RabbitListener comment

For example, in the method onMessage @RabbitListener add annotations, also you need to add another comment @RabbitHandler, the code is listening to consumers.

Establish a binding, written on the queue, set on the Exchange Value, if persistent, set the type of Exchange, the expression is set to true and routing key. In this simple manner, it can be completed before the complex code logic. Meanwhile recommended configuration into the configuration file, dynamic access. If there is no corresponding mq queue, Exchange, etc., they can also create annotation statement , you can test yourself!

2.2.1 New Project springboot-consumer

pom.xml



<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.cp</groupId>
	<artifactId>springboot-consumer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>springboot-consumer</name>
	<description>springboot-consumer</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>



复制代码

RabbitReceiver.java news producer


@Component
public class RabbitReceiver {

	
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = "queue-1", 
			durable="true"),
			exchange = @Exchange(value = "exchange-1", 
			durable="true", 
			type= "topic", 
			ignoreDeclarationExceptions = "true"),
			key = "springboot.*"
			)
	)
	@RabbitHandler
	public void onMessage(Message message, Channel channel) throws Exception {
		System.err.println("--------------------------------------");
		System.err.println("消费端Payload: " + message.getPayload());
		Long deliveryTag = (Long)message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
		//手工ACK,获取deliveryTag
		channel.basicAck(deliveryTag, false);
	}
}


复制代码

application.properties

spring.rabbitmq.addresses=localhost:5672
spring.rabbitmq.username=user_cp
spring.rabbitmq.password=123456
spring.rabbitmq.virtual-host=/vhost_cp
spring.rabbitmq.connection-timeout=15000

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

复制代码

Run Application, see previous messages sent in the production end, whether the consumer could be.

Print results

Print results
Because before I tested multiple messages, so the consumer when there are so many here.

3. optimized code

  • Custom Java Object Message
  • @RabbitListener annotation configuration to a dynamic configuration

@Payload: Specifies the specific message body Body. @Headers: get Headers.

3.1 Consumer end optimization

1, first define a target Order


public class Order implements Serializable {

	private String id;
	private String name;
	
	public Order() {
	}
	public Order(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}


复制代码

Note: We transfer object, it must be serialized. Otherwise transmission fails.

2, RabbitReceiver add a listener


/**
	 * 
	 * 	spring.rabbitmq.listener.order.queue.name=queue-2
		spring.rabbitmq.listener.order.queue.durable=true
		spring.rabbitmq.listener.order.exchange.name=exchange-2
		spring.rabbitmq.listener.order.exchange.durable=true
		spring.rabbitmq.listener.order.exchange.type=topic
		spring.rabbitmq.listener.order.exchange.ignoreDeclarationExceptions=true
		spring.rabbitmq.listener.order.key=springboot.*
	 * @param order
	 * @param channel
	 * @param headers
	 * @throws Exception
	 */
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = "${spring.rabbitmq.listener.order.queue.name}", 
			durable="${spring.rabbitmq.listener.order.queue.durable}"),
			exchange = @Exchange(value = "${spring.rabbitmq.listener.order.exchange.name}", 
			durable="${spring.rabbitmq.listener.order.exchange.durable}", 
			type= "${spring.rabbitmq.listener.order.exchange.type}", 
			ignoreDeclarationExceptions = "${spring.rabbitmq.listener.order.exchange.ignoreDeclarationExceptions}"),
			key = "${spring.rabbitmq.listener.order.key}"
			)
	)
	@RabbitHandler
	public void onOrderMessage(@Payload com.cp.springboot.entity.Order order, 
			Channel channel, 
			@Headers Map<String, Object> headers) throws Exception {
		System.err.println("--------------------------------------");
		System.err.println("消费端order: " + order.getId());
		Long deliveryTag = (Long)headers.get(AmqpHeaders.DELIVERY_TAG);
		//手工ACK
		channel.basicAck(deliveryTag, false);
	}

复制代码

It has written to the application.properties configuration, the dynamic acquisition. Our company can also like, like put them into the configuration center. For example: Ctrip Open Source Configuration Center Apollo

3、application.properties


spring.rabbitmq.listener.order.queue.name=queue-2
spring.rabbitmq.listener.order.queue.durable=true
spring.rabbitmq.listener.order.exchange.name=exchange-2
spring.rabbitmq.listener.order.exchange.durable=true
spring.rabbitmq.listener.order.exchange.type=topic
spring.rabbitmq.listener.order.exchange.ignoreDeclarationExceptions=true
spring.rabbitmq.listener.order.key=springboot.*

复制代码

3.2 Production end optimization

1, it is also an Order object must remain consistent with the consumer side.

2, RabbitSender added to send a message


//发送消息方法调用: 构建自定义对象消息
public void sendOrder(Order order) throws Exception {
	rabbitTemplate.setConfirmCallback(confirmCallback);
	rabbitTemplate.setReturnCallback(returnCallback);
	//id + 时间戳 全局唯一 
	CorrelationData correlationData = new CorrelationData("0987654321");
	rabbitTemplate.convertAndSend("exchange-2", "springboot.def", order, correlationData);
}


复制代码

3, add a test method


@Test
public void testSender2() throws Exception {
	 Order order = new Order("001", "第一个订单");
	 rabbitSender.sendOrder(order);
	 //防止资源提前关闭,ConfirmCallback异步回调失败
	 Thread.sleep(2000);
}

复制代码

3.3 Test

Run testSender2 () method.

End print production news

End print production news

Consumer-side printing messages

Consumer-side printing messages

So far, RabbitMQ integration SpringBoot completed, in practice, the use of scenarios is almost the same.

The end of the sentence

Welcome attention to personal micro-channel public number: Coder program for the latest original technical articles and free learning materials, a lot more boutique mind maps, interview data, PMP preparation materials waiting for you to lead, allowing you to learn technical knowledge anytime, anywhere! Create a qq group: 315 211 365, we welcome into the group exchange study together. Thank you! Can also be introduced to the side of a friend in need.

Articles included to Github: github.com/CoderMerlin... Gitee: gitee.com/573059382/c... welcome attention and star ~

Micro-channel public number

Reference article:

"RabbitMQ messaging middleware succinctly"

recommended article:

Messaging middleware --RabbitMQ (seven) advanced features all here! (On)

Messaging middleware --RabbitMQ (eight) advanced features all here! (At)

Messaging middleware --RabbitMQ (nine) RabbitMQ integrate Spring AMQP combat! (all)

Guess you like

Origin juejin.im/post/5d613297518825627f0d59bd