1. Brief introduction
In most applications, message service middleware can be used to improve system asynchronous communication and expand decoupling capabilities
- Two important concepts in message services:
message broker and destination. When the message sender sends a message, it will be taken over by the message agent, which guarantees that the message is delivered to the specified destination. - Message queues mainly have two forms of destinations:
queue: point-to-point message communication (point-to-point)
topic: publish/subscribe message communication
Two, installation
Open the virtual machine, run Linux, open SmarTTY, enter docker pull rabbitmq:3-management
, and download
docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq d55229deb03e
- -d run in the background
- It has two more ports, so just -p twice
- --Name is myrabbitmq
- The back pile is the ID of my rabbitmq, checked with docker images
Then enter in the browser http://192.168.0.102:15672/
, of course, this IP is my SmarTTY connected to Linux, what is my own, see the docker I wrote before
Go in, login account password, the default is guest
Three, RabbitMQ
The producer publishes the message to the Exchange, the message finally arrives in the queue and is received by the consumer, and the Binding determines which queue the exchange's message should be sent to.
When Exchange distributes messages, there are differences according to different distribution strategies. There are currently four types: direct, fanout, topic, and headers .
1. Topic Exchanger
The topic switch distributes the routing key attribute of the message through pattern matching, and matches the routing key with a pattern. At this time, the queue needs to be bound to a pattern. It divides the string of routing key and binding key into words, which are separated by dots. It also recognizes two wildcard characters: the symbol "#" and the symbol "*". #Match 0 or more words, *Match one word.
2. Test it first
Diagram of the video tutorial
Follow the video tutorial to do the test, I don’t know why this is happening. . . Do a few exchanges, and then bind the queue,
3. Create 3exchange
The main
ones are these two boxes. That Durability
: option, Duiable means persistence. After opening it next time, the exchange is still there, and the other one means it disappears after closing.
4. Add 4 queues
5. Binding queues to all 3 exchanges
Choose which one to tie, click in
- But ah, it’s a bit different in exchange.topic, because exchange.topic is not bound to all, the route name needs to be changed, as explained later
See the picture at the beginning, exchange.direct and exchange.fanout are bound to the 4 queues, exchange.topic is atguigu.#
bound (atguigu as the head) and *.news
bound (the end of news)
exchange.direct and exchange.fanout are both bound Into this
Then, exchange.topic:
- what does this mean? Said later
6. Test
1)`exchange.direct
For example, when we exchange.direct
send an atguigu request in China, only the atguigu queue can accept it, because the exchange uses direct and the route name is atguigu . The name of the route is specified to send information. Other queues have different names and cannot be received.
- If the type is direct, specify who to send to
2)exchange.fanout
The type is fanout
that no matter what is specified, the queue in exchange.fanout will receive it. For example, send a request in exchange.fanout
- Only atguigu’s ready is 2 because the above example is atguigu request
3)exchange.topic
Sending in exchange.topic hello.news
, it seems that this does not exist, but look carefully
because the topic
type is used, so the technology can be fuzzy matching. (This should be understood as binding, because the queue is written at the beginning, and then the exchange has some binding with each queue) Then the atguigu.news queue accepts *.news and can accept it. The gulixueyuan.news queue accepts *.news and can also accept it.
Four, project testing
1. Configuration
application.yml:
spring:
rabbitmq:
host: 192.168.0.102
username: guest
password: guest
2. Send a message
Can be automatically imported with @Autowired
@SpringBootTest
class SpringBootAmqpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
// rabbitTemplate.send(String exchange, String routeKey, Message var3)
// Message(byte[] body, MessageProperties messageProperties) Message为一个数组和一个头消息
// convertAndSend(String var1, String var2, Object var3)
// 其中,Object var3默认为消息体,会自动序列化发送过去的
Map<String,Object> map = new HashMap<>();
map.put("msg","这是一个信息");
rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",map);
}
send(String exchange, String routeKey, Message var3)
: Exchange name, route name, and message. The message consists of message content and message headerconvertAndSend(String var1, String var2, Object var3)
, The send is too troublesome, there is this method, Object var3 will be automatically converted to serialization to send messages
3. Accept the message
@Test
public void test(){
Message receive = rabbitTemplate.receive("atguigu.news");
System.out.println(receive);
}
(Body:’{msg=这是一个信息}’ MessageProperties [headers={}, contentType=application/x-java-serialized-object, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=true, receivedExchange=exchange.direct, receivedRoutingKey=atguigu.news, deliveryTag=1, messageCount=0])
4. The sent message becomes JSON type
As you can see, both sending and receiving are serialized and deserialized. It is better to convert to JSON, just add a configuration class.
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter(){
// 把消息转化为JSON格式
return new Jackson2JsonMessageConverter();
}
}
Send
again and accept again
class org.springframework.amqp.core.Message
(Body:’{“msg”:“这是一个信息”}’ MessageProperties [headers={ ContentTypeId=java.lang.Object, KeyTypeId=java.lang.Object, TypeId=java.util.HashMap}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=true, receivedExchange=exchange.direct, receivedRoutingKey=atguigu.news, deliveryTag=1, messageCount=0])
This exchange.direct
is how it is sent to , and the same is true for other types of exchanges.
5. Automatically accept messages
In order to show better, we create a class with the toString method written in it,
public class Person {
String name;
int age;
//xxx
}
Create a Service layer to automatically receive messages from a certain queue
@Service
public class PersonService {
@RabbitListener(queues = "atguigu.news")
public void receive(Person person){
System.out.println("收到消息"+person);
}
}
@RabbitListener
: You can put multiple queues to automatically accept the things in the queue. If the parameter is used, write Person, that is, if the sent JSON is Person, it can be received, if not, it is the Message type
Turn on the annotation of automatically accepting messages in the main program
@EnableRabbit
@SpringBootApplication
public class SpringBootAmqpApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAmqpApplication.class, args);
}
}
@EnableRabbit
: Turn on the comment of automatically accepting messages
Test class
@SpringBootTest
class SpringBootAmqpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",new Person("小强",22));
}
A message of a custom class is sent here
Received the message Person{name='Xiaoqiang', age=22}
Because it accepts how to output something, it is written by the service layer
6. If it is automatically accepted as Message type
A method of the service layer
@RabbitListener(queues = "atguigu")
public void receive2(Message message){
System.out.println(message.getBody());
System.out.println(message.getMessageProperties());
}
Still send the Person object, but the queue is atguigu, and the above also accepts atguigu, but the acceptance type is Message
@Test
void contextLoads() {
rabbitTemplate.convertAndSend("exchange.direct","atguigu",new Person("小强",22));
}
[B@5e012317
MessageProperties [headers={ TypeId=com.qiang.Bean.Person}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=exchange.direct, receivedRoutingKey=atguigu, deliveryTag=1, consumerTag=amq.ctag-Ws2bRFLJ6Y3d7JXvrKVCTQ, consumerQueue=atguigu]
Five, code replaces interface operations
The creation of exchange, queue, and binding that we did before can all be implemented in Java.
Continue to do it in the test class
@Test
public void create(){
amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
amqpAdmin.declareQueue(new Queue("amqpadmin.queue",true));
amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp.test",null));
}
DirectExchange
: There is at most this containerDirectExchange(String name, boolean durable, boolean autoDelete, Map<String, Object> arguments)
, but there is also a container, just write the first one. Durable is whether it is persistent, and whether boolean autoDelete is automatically deleted, Map does not know. . .Queue
the sameBinding
:Binding(String destination, Binding.DestinationType destinationType, String exchange, String routingKey, @Nullable Map<String, Object> arguments)
- destination: destination, which queue to bind to
- Binding.DestinationType destinationType: Just follow along. . .
- exchange: which exchange
- routingKey: What is the routing name?
- @Nullable Map: I don't know. . . .
The code so far: spring-boot-AMQP