In the previous chapters, in particular, "consumer local affairs" we did not make any configuration, why the transaction took effect (regardless of the combination of relational database, the combination of MQ transaction is still in effect, but the relational database transactions are not as a whole transaction management), Let's explore how spring can help us achieve this by analyzing the source code.
Summary of this chapter 1, Jmslistener annotation 2, other consumption methods to achieve (3) 3, Distributed transaction support
Jmslistener annotation 1, through the Jmslistener annotation monitoring consumption, realize the asynchronous consumption;
2. The need to support @jmslistener annotations in official documents requires that you add @enablejms annotations in any @configuration class, and you also need to configure Defaultjmslistenercontainerfactory Instance of the bean, as follows
Registers the relevant bean instance with the jmsannotationdrivenconfiguration in Springboot. It can be found in registered Defaultjmslistenercontainerfactoryconfigurer to support JTA Distributed transaction Management, And the Configure method in Defaultjmslistenercontainerfactoryconfigurer can see the following code: if (This.transactionmanager!= null) { Factory.settransactionmanager (This.transactionmanager); else {factory.setsessiontransacted (boolean.valueof (True)), which supports the JMS internal session transaction mechanism by default when no external transaction manager is configured. This is a good explanation for why the consumer local transaction under the @jmslistener annotation has been in effect without any configuration, and can even effectively handle the consumption and production of the message in a transaction. Continue to look at the source code, in defaultjmslistenercontainerfactory defined the creation of the Defaultmessagelistenercontainer message listening container, The settings for many subsequent listening parameters are set (e.g. Durablesubscriptionname supports persistent subscriptions);
And Defaultjmslistenercontainerfactory inherits from Abstractjmslistenercontainerfactory, Which defines the method that really creates the Defaultmessagelistenercontainer object, public C Createlistenercontainer (Jmslistenerendpoint endpoint) { Abstractmessagelistenercontainer instance = Createcontainerinstance (); ... endpoint.setuplistenercontainer (instance); Initializecontainer (instance); return instance; } protected abstract C createcontainerinstance (); protected void Initializecontainer (C instance) {} The question is, when did spring call the The Createlistenercontainer method creates Defaultmessagelistenercontainer, and in Jmslistenerendpointregistrar there are several ways to define
Where Resolvecontainerfactory gets registered in the Jmsannotationdrivenconfiguration defaultjmslistenercontainerfactory, provides register** method to register the corresponding endpoint and continue tracking This.endpointRegistry.registerListenerContainer (descriptor.endpoint,resolvecontainerfactory ( Descriptor); method, in fact now Jmslistenerendpointregistry, the red-labeled part can see that we are just getting through the defaultjmslistenercontainerfactory call The Createlistenercontainer method defines the final message listener container Defaultmessagelistenercontainer. It's not over here yet. The final message listener event processing is handled in the Onmessage-->invokelistenermethod method in Messagelisteneradapter.
Above is the Java configuration way, we can also through the XML configuration, source website screenshot:
Other ways of consuming the way one, from the official can see the following description, if we do not use the @jmslistener annotation for message consumption monitoring, You can configure jmslistenerconfigurer in code to replace @jmslistener with Jmslistenerendpoint
Spring provides simplejmslistenerendpoint to assist us in configuration, Jmslistenerendpointregistrar also involved in the above @jmslistener, The most important thing is Endpoint.setmessagelistener (message-> {//processing}); The listener processing of the final message is implemented in our defined MessageListener. We need to define the implementation class for the message Listener MessageListener, which has 3 implementations: MessageListener, Sessionawaremessagelistener, and Messagelisteneradapter. 1, MessageListener: the implementation of asynchronous listening, through the OnMessage method to process a unique parameter message. MessageListener's design is purely for receiving messages, and if we use MessageListener to process incoming messages, we need to send a message informing each other that we have received the message, So this time we need to be in the code to retrieve a connection or session; 2, Sessionawaremessagelistener:sessionawaremessagelistener is provided for us by spring and is not a standard JMS messagelistener. Sessionawaremessagelistener is designed to make it easier for us to send a reply message after receiving a message, and it also provides us with a OnMessage method for handling incoming messages, but this method can receive two parameters at the same time, One is the message messages that are currently received, and the other is the session object that can be used to send messages. 3, the Messagelisteneradapter:messagelisteneradapter class implements the MessageListener interface and the Sessionawaremessagelistener interface, Its main function is to convert the received message into a type, and then to give it to a normal Java class for processing in the form of reflection. Another major feature is the ability to automatically send return messages. When the return value of the method we used to process the received message is not empty, spring automatically encapsulates it as a JMS message and then automatically replies. After replying to the consumer has two kinds of definition: 3.1, by sending the message of sThe Etjmsreplyto method specifies the destination of the reply message corresponding to the message. 3.2, through the Messagelisteneradapter defaultresponsedestination attribute to specify.
Mode two: Through XML configuration, the official also supports the JMS namespace configuration, and supports the use of @jmslistener annotation listening
Official Configuration case
In Jms:listener, ref is the listener class that we need to define the implementation, and the way of listening is introduced, we use the inheritance Messagelisteneradapter class to implement more. as follows: @Component ("OrderService") public class OrderService extends messagelisteneradapter{@JmsListener (destination= " Queue.orders ", concurrency=" 5-10 ") public void PlaceOrder (Message message, Sessions session) throws JMSException {try { Object object= Getmessageconverter (). Frommessage (message); System.out.println (Object.ToString ()); SYSTEM.OUT.PRINTLN (session); Message.acknowledge ()//At this time we can manually sign the catch (Messageconversionexception | JMSException e) {e.printstacktrace ();}}}
Mode three: According to the above @jmslistener source analysis, in fact, we have been able to notice, whether it is defaultjmslistenercontainerfactoryconfigurer, Defaultjmslistenercontainerfactory are helping us step closer to Defaultjmslistenercontainer, In fact, we can directly register Defaultjmslistenercontainer instance to implement the listening processing of messages, can be implemented through Java or XML configuration, basically the following format: <!-- Configure JMS Connection factory --> <bean id = "Myconnectionfactory" class = "Org.springframework.jms.connection.CachingConnectionFactory" > <!-- session Cache quantity --> <property name = "Sessioncachesize" value = "Ten" /> <!-- recipient id --> <property name = "ClientId" value = "client_01" /> & nbsp <property name = "Targetconnectionfactory" > <bean class = " Org.apache.activemq.ActiveMQConnectionFactory "> <!-- mq address --> <property name = " Brokerurl " value =" tcp://localhost:61626 " /> </bean> </ property> </bean> <!-- Listener message destination (a subject) -- > <bean id = "Mydestination" class = "Org.apache.activemq.command.ActiveMQTopic" > &nb sp; <!-- Message subject name --> <constructor-arg index = "0" value = "My.topic" /> </bean> <!-- Consumer message configuration (Define yourself)--> <bean id = "Mytopicconsumer" class = "Com.shf.jms.JMS Receiver " /> <!-- Message listener --> <bean id = "Mytopiclistener" class = "Org.springframework.jms.listener.adapter.MessageListenerAdapter" > <constructor-arg ref = "Mytopicconsumer" /> <!-- receiving messagesMethod name --> <property name = " Defaultlistenermethod " value =" Receive " /> & nbsp <!-- No message conversion --> <property Name = "Messageconverter" ><null/></property> </bean> <!-- Message monitor container --> <bean id = "Mylistenercontainer" class = "Org.springframework.jms.listener.DefaultMessageListenerContainer" > <property name = "ConnectionFactory" ref = "Myconnectionfactory" /> &N bsp; <!-- Publish subscriptionsMode --> <property name = "Pubsubdomain " value =" true "/> <!-- message Persistence -- > <property name = "Subscriptiondurable" & nbsp Value = "true"/> <property name = " ReceiveTimeout " value =" 10000 "/> <!-- Receiver Id --> <property name = " ClientId " value =" client_01 " /> < Property name = "Durablesubscriptionname" value = "client_01"/> &n bsp; <property name = "Destination" &NBsp ref = "Mydestination" /> <property Name = "MessageListener" ref = "Mytopiclistener" /> </bean> & nbsp; the XML configuration into a Java configuration is not complicated and is not implemented here.
The Support Message Listener container (Messagelistenercontainer) for a distributed transaction is used to accept messages from a JMS message queue and then push to register with the message Listener (MessageListener) inside it. Spring provides two standard JMS message listening containers, featuring the following: Simplemessagelistenercontainer: At startup, create a fixed number of JMS sessions and a consumer, Use the standard Jmsmessageconsumer.setmessagelistener () method to register the listener and allow the JMS provider to return the listener. Defaultmessagelistenercontainer: Supports dynamic adaptation at run time and can participate in external managed transactions. Each received message is registered as an XA transaction using Jtatransactionmanager, and thus can be handled with the full use of XA transaction semantics. Because many scenarios in the actual project require the implementation of XA transactions, we usually use the Defaultmessagelistenercontainer configuration message listening container.
Also note that in the section "Optimizing Producer connection factories (with session caching)" We verify that transactions can take effect regardless of whether the xa-connectionfactory is adopted, and that, in the consumer, With the Jtatransactionmanager need to synchronize the use of activemqxaconnectionfactory.
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.
A Free Trial That Lets You Build Big!
Start building with 50+ products and up to 12 months usage for Elastic Compute Service