When a producer publishes a message through the channel's Basicpublish method, there are usually several parameters that need to be set, so it is necessary to understand the specific meaning and function of these parameters, and to see the channel interface, we find that there are 3 overloaded Basicpublish methods
void Basicpublish (String Exchange, String Routingkey, basicproperties props, byte[] body) throws Ioexception;void Basicpu Blish (String Exchange, String Routingkey, Boolean mandatory, basicproperties props, byte[] body) throws IOException; void Basicpublish (String Exchange, String Routingkey, Boolean mandatory, Boolean immediate, basicproperties props, byte[] Body) throws IOException;
the parameters they shared were:
Exchange: Switch name
Routingkey: Routing Key
Props: Message attribute fields, such as message header information, etc.
Body: Message body part
In addition to this, there are two parameters, mandatory and immediate, since RabbitMQ3.0 no longer supports the immediate flag, so we focus on the mandatory flag
the role of mandatory:
When the mandatory flag bit is set to true, if Exchange cannot find a suitable queue store message based on its type and message Routingkey, the broker invokes the Basic.return method to return the message to the producer; When mandatory is set to false, the broker will discard the message directly; in layman's words, the mandatory flag tells the broker that the proxy server will send the message to a queue at least, or return the message to the sender;
Below we test the role of the mandatory flag with several examples:
Test 1: Set the mandatory flag, and exchange is not bound to a queue
public class Producertest {public static void main (string[] args) {String exchangename = "Confirmexchange"; String queuename = "Confirmqueue"; String Routingkey = "Confirmroutingkey"; String Bindingkey = "Confirmbindingkey"; int count = 3; ConnectionFactory factory = new ConnectionFactory () factory.sethost ("172.16.151.74"); Factory.setusername ("Test"); Factory.setpassword ("test"); Factory.setport (5672);//create producer sender producer = new Sender (Factory, Count, Exchangename, Routingkey);p roducer.run ();}} Class sender{private connectionfactory factory;private int count;private string exchangename;private string RoutingKey; Public Sender (connectionfactory factory,int count,string exchangename,string routingkey) {this.factory = factory; This.count = Count;this.exchangename = Exchangename;this.routingkey = Routingkey;} public void Run () {try {Connection Connection = factory.newconnection (); Channel channel = Connection.createchannel ();//Create Exchangechannel.exchangedeclare (Exchangename, "direct", true, False , null);//Send persistent message for (int i = 0;i < count;i++) {//The first parameter is Exchangename (by default, there is a "" name for Exchange on the proxy server side, So if we do not create exchange, we can set this parameter directly to "", if we create exchange we need to set this parameter to the name of the exchange created, the second parameter is the routing key Channel.basicpublish ( Exchangename, Routingkey, True, Messageproperties.persistent_basic, ("First" + (i+1) + "message"). GetBytes ());}} catch (Exception e) {e.printstacktrace ();}}}
Line 45th We set Basicpublish's third parameter mandatory to true, indicating that the mandatory flag is turned on, but we are not binding any queues for the current exchange;
The following output is seen through the Wireshark clutch:
As you can see, the Basic.return method is finally executed, the message issued by the publisher is returned to the publisher, and the arguments parameter section of the protocol is seen, the Reply-text field value is: No_route, indicating that the message is not routed to the appropriate queue;
So how do we get messages that are not properly routed to the appropriate queue? This time can be achieved by setting the Returnlistener listener for channel channels, the implementation code is shown below:
public class Producertest {public static void main (string[] args) {String exchangename = "Confirmexchange"; String queuename = "Confirmqueue"; String Routingkey = "Confirmroutingkey"; String Bindingkey = "Confirmbindingkey"; int count = 3; ConnectionFactory factory = new ConnectionFactory () factory.sethost ("172.16.151.74"); Factory.setusername ("Test"); Factory.setpassword ("test"); Factory.setport (5672);//create producer sender producer = new Sender (Factory, Count, Exchangename, Routingkey);p roducer.run ();}} Class sender{private connectionfactory factory;private int count;private string exchangename;private string RoutingKey; Public Sender (connectionfactory factory,int count,string exchangename,string routingkey) {this.factory = factory; This.count = Count;this.exchangename = Exchangename;this.routingkey = Routingkey;} public void Run () {try {Connection Connection = factory.newconnection (); Channel channel = Connection.createchannel ();//Create Exchangechannel.exchangedeclare (Exchangename, "direct", true, False , null);//Send persistent message for (int i = 0;i < count;i++) {//The first parameter is Exchangename (by default the proxy server is present with the name of Exchange,// So if we do not create exchange, we can directly set this parameter to "", if Exchange is created//We need to set this parameter to the name of the exchange created, the second parameter is the routing key Channel.basicpublish ( Exchangename, Routingkey, True, Messageproperties.persistent_basic, ("First" + (i+1) + "message"). GetBytes ());} Channel.addreturnlistener (New Returnlistener () {@Overridepublic void Handlereturn (int arg0, string arg1, String arg2, String Arg3, Basicproperties arg4, byte[] arg5) throws IOException {//Here is where the callback after the Basic.return is executed string message = new string (ARG5); SYSTEM.OUT.PRINTLN ("Basic.return Returns the result:" +message);}); catch (Exception e) {e.printstacktrace ();}}}
After the Returnlistener listener is set, the broker (proxy server) will call back the Handlereturn method of line 52nd after issuing the Basic.return method, in which we can do the re-publishing of the message;
Test 2: sets the mandatory flag and is the Exchange bound queue (the routing key and binding key are consistent)
public class Producertest {public static void main (string[] args) {String exchangename = "Confirmexchange"; String queuename = "Confirmqueue"; String Routingkey = "Confirmroutingkey"; String Bindingkey = "Confirmroutingkey";//string bindingkey = "Confirmbindingkey"; int count = 3; ConnectionFactory factory = new ConnectionFactory () factory.sethost ("172.16.151.74"); Factory.setusername ("Test"); Factory.setpassword ("test"); Factory.setport (5672);//create producer sender producer = new Sender (Factory, Count, Exchangename, Queuename,routingkey,bindingkey);p roducer.run ();}} Class sender{private connectionfactory factory;private int count;private string exchangename;private string queueName; private string Routingkey;private string Bindingkey;public Sender (connectionfactory factory,int count,string exchangename,string queuename,string routingkey,string bindingkey) {this.factory = Factory;this.count = count; This.exchangename = Exchangename;this.queuename = Queuename;this.routingkey = Routingkey;this.bindingkey =Bindingkey;} public void Run () {try {Connection Connection = factory.newconnection (); Channel channel = Connection.createchannel ();//Create Exchangechannel.exchangedeclare (Exchangename, "direct", true, False , null);//Create Queue Channel.queuedeclare (QueueName, True, False, false, null);//Bind Exchange and Queuechannel.queuebind ( QueueName, Exchangename, Bindingkey);//Send persistent message for (int i = 0;i < count;i++) {//The first parameter is Exchangename (by default there is a "" on the proxy server side) Name of Exchange,//So if you do not create exchange then we can directly set this parameter to "", if the exchange is created//We need to set this parameter to the name of the exchange created), The second parameter is the routing key Channel.basicpublish (Exchangename, Routingkey, True, Messageproperties.persistent_basic, ("+" + (i+1) + "message" ). GetBytes ());} Channel.addreturnlistener (New Returnlistener () {@Overridepublic void Handlereturn (int arg0, string arg1, String arg2, String Arg3, Basicproperties arg4, byte[] arg5) throws IOException {//Here is where the callback after the Basic.return is executed string message = new string (ARG5); SYSTEM.OUT.PRINTLN ("Basic.return Returns the result:" +message);}); catch (Exception e) {e.printstacktrace ();}}}
The Basic.return method is not called through the catch Packet discovery, and the RABBITMQ management interface discovers that the message has reached the queue;
Test 3: set the mandatory flag, and Exchange bound queues (routing keys and binding keys are inconsistent)
The code is the 6th line of comments in Test 2, the 7th line of comments Open, notice that at this time the Routingkey and Bindingkey is inconsistent, at this time we run the program, while grasping the package to get the following:
Note that we sent three messages, Then the corresponding should be performed three times Basic.return, where the first and second Basic.return appear on one line, the third is a single line, do not mistakenly think that only two times, from the specific return of the agreement we also see the Reply-text field value is No_ ROUTE, a phenomenon that has been seen in Test 1;
Here, we understand the role of the mandatory flag: When the message is not routed to the appropriate queue, the message is returned to the message publisher, and we test the circumstances under which the message does not reach the appropriate queue. Test 1 demonstrates that the message created by Exchange but not tied to his queue has not reached the appropriate queue, and test 3 shows that the queue was created while the exchange was created, but when you bind the two, The messages that were used by the Bindingkey and the Rountingkey inconsistent with the message publisher did not reach the appropriate queue;
Resources:
RabbitMQ (ii) AMQP protocol mandatory and immediate flag bit differences
The mandatory of RABBITMQ
Deep learning RABBITMQ (i): the role of the mandatory logo