(transfer) Sping+ActiveMQ integration



The integration of Spring and ActiveMQ needs to include the following jar packages in the project (one is indispensable): activeio-core-3.1.4.jar, activemq-all-5.13.2.jar, activemq-pool-5.13.2.jar , commons-pool2-2.4.2.jar, these jars can be found under /lib/optional/ in the ActiveMQ installation package, or downloaded from here.

Configuring ConnectionFactory

ConnectionFactory is used to generate links to the JMS server. Spring provides us with multiple ConnectionFactory, SingleConnectionFactory and CachingConnectionFactory. SingleConnectionFactory will always return the same connection for requests to establish a JMS server connection, and will ignore the Connection's close method call. CachingConnectionFactory inherits SingleConnectionFactory, so it has all the functions of SingleConnectionFactory, and it also adds a caching function that can cache Session, MessageProducer and MessageConsumer.

The ConnectionFactory provided by Spring is only used by Spring to manage the ConnectionFactory. The ConnectionFactory that actually generates the link to the JMS server must be provided by the JMS service provider, and it needs to be injected into the ConnectionFactory provided by Spring. The ConnectionFactory provided by ActiveMQ is used here, so define As follows (10.10.195.187 is the blogger's test ip address):


<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://10.10.195.187:61616" />
    </bean>
    <bean id=" connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
        <property name="targetConnectionFactory" ref="targetConnectionFactory"/>
    </bean>
ActiveMQ provides us with a PooledConnectionFactory, which can be used by injecting an ActiveMQConnectionFactory into it To pool Connection, Session and MessageProducer, which can greatly reduce our resource consumption. When using PooledConnectionFactory, we define a ConnectionFactory like this:


<bean id="targetConnectionFactory" class="org.apache.activemq.

   </bean>
   <bean id="poolConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"  >
       <property name="connectionFactory" ref="targetConnectionFactory" />
       <property name="maxConnections" value="10"/>
   </bean>
   <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
       <property name="targetConnectionFactory" ref="poolConnectionFactory"/>
   </bean>
这里也可以去掉spring提供的SingleConnectionFactory,类似这样:


<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://10.10.195.187:61616" />
    </bean>
    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" >
        <property name="connectionFactory" ref="targetConnectionFactory" />
        <property name="maxConnections" value="10"/>
    < /bean>
Configure the message sender (producer) After

configuring the ConnectionFactory, we need to configure the producer. The producer is responsible for producing messages and sending them to the JMS server, which usually corresponds to one of our business logic service implementation classes. But how does our service implementation class send messages? This is usually achieved by using the JmsTemplate class provided by Spring, so the core of configuring the producer is to configure the JmsTemplate for message sending. For the message sender, it needs to know where to send the message when it sends the message. For this reason, when we define the JmsTemplate, we need to inject a ConnectionFactory object provided by Spring into it.

Add to the spring configuration file:


<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
       <property name="connectionFactory"

Add in the Java related processing files (the @Inject annotation is used here, of course @Autowired can also be used):


@Inject
   @Named("jmsTemplate")
   private JmsTemplate jmsTemplate;
so that the related information can be processed through the jmsTemplate object, for example:


jmsTemplate.convertAndSend("sqlQueue",sql);
When using JmsTemplate for message sending, we need to know the destination of the message, that is, Destination. There is a Destination interface used to represent the destination in Jms. It does not have any method definition in it, but is only used as a sign. When we do not specify the destination when using JmsTemplate for message sending, the default Destination will be used. The default Destination can be defined by the property defaultDestination or defaultDestinationName when defining the jmsTemplate bean object. For example, defaultDestinationName is an ordinary string. Two types of Destinations are implemented in ActiveMQ, one is the point-to-point ActiveMQQueue, and the other is the ActiveMQTopic that supports the subscription-publishing mode.


<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <
        </constructor-arg>
    </bean>
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg>
            <value>topic</value>
        </constructor-arg>
    </bean>
The example above can be added to the Java program:


@Inject
   @Named("queueDestination")
   private Destination queueDestination;
and then [jmsTemplate.convertAndSend("sqlQueue",sql);] can be changed to [jmsTemplate.convertAndSend] (queueDestination,sql);]
You can also modify jmsTemplate like this:


<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="queueDestination"/>
    </bean>
or:


<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref= "connectionFactory"/>
        <property name="defaultDestinationName" value="sqlQueue"/>
    </bean>
and then call this in the java program: jmsTemplate.convertAndSend(sql);

configure the message receiver (consumer)

After the producer sends a message to the specified destination Destination, the next step is for the consumer to consume the message from the specified destination. So how does the consumer know that a producer has sent a message to the specified destination Destination? This is achieved through the MessageListenerContainer, a message listener container encapsulated by Spring, which is responsible for receiving information and distributing the received information to the real MessageListener for processing. Each consumer needs a corresponding MessageListenerContainer for each destination. For the message monitoring container, in addition to knowing which destination to listen to, it also needs to know where to listen, that is to say, it also needs to know which JMS server to listen to. This is done by injecting a message when configuring the MessageConnectionFactory. ConnectionFactory to achieve. So when we configure a MessageListenerContainer, there are three properties that must be specified, one is the ConnectionFactory that indicates where to listen from, the other is the Destination that indicates what to listen for, and the other is the MessageListener that processes the message after receiving the message.

Spring has heard of two types of MessageListenerContainer for us: SimpleMessageListenerContainer and DefaultMessageListenerContainer. MessageListenerContainer: SimpleMessageListenerContainer will create a session session and consumer Consumer at the beginning, and will use the standard JMS MessageConsumer.setMessageListener() method to register the listener and let JMS provide a callback function for calling the listener. It does not dynamically adapt to runtime needs and participate in external transaction management. Compatibility-wise, it is very close to the stand-alone JMS specification, but is generally not compatible with J2EE's JMS limitations. In most cases, we still use DefaultMessageListenerContainer, compared with MessageListenerContainer: SimpleMessageListenerContainer, it will dynamically adapt to the needs of the runtime and can participate in external transaction management. It is a good balance of JMS provider requirements, advanced features such as transaction participation and compatibility with J2EE environment.

Add to the spring configuration file:


<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
       <constructor-arg>
           <value>sqlQueue</value>
       </constructor-arg>
   </bean>
   <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
       <property name="connectionFactory" ref="poolConnectionFactory" />
       <property name="messageListener" ref="jmsQueueReceiver" />
       <property name="destination" ref="queueDestination" />
   </bean>
其中的jmsQueueReceiver代码如下:


import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.springframework.stereotype.Component;

@Component("jmsQueueReceiver")
public class JmsQueueReceiver implements MessageListener
{
    @Override
    public void onMessage(Message messgae)
    {
        if(messgae instanceof TextMessage)
        {
            TextMessage textMessage = (TextMessage) messgae;
            try
            {
                String text = textMessage.getText();
                System.out.println("######################["+text+"]######################");
            }
            catch (JMSException e)
            {
                e.printStackTrace();
            }
        }
    }
}
事务管理

Spring provides a JmsTransactionManager for transaction management of the JMS ConnectionFactory. This will allow JMS applications to take advantage of Spring's transaction management features. JmsTransactionManager binds a ConnectionFactory/Session pair from the specified ConnectionFactory to the thread when performing local resource transaction management. JmsTemplate will automatically detect such transactional resources and act on them accordingly.

In a J2EE environment, ConnectionFactory pools Connections and Sessions so that these resources are effectively reused throughout the transaction. In an independent environment, when using Spring's SingleConnectionFactory, all transactions will share a Connection, but each transaction will keep its own independent Session.

JmsTemplate can handle distributed transactions using JtaTransactionManager and JMS ConnectionFactory that can be distributed.

In the application of Spring integrated JMS, if we want to perform local transaction management, it is very simple. We only need to specify the sessionTransacted property as true (default is false) when defining the corresponding message listener container:


<bean id="listenerContainer" class ="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="messageListener" ref="jmsQueueReceiver" />
        <property name="destination" ref="queueDestination" />
        <property name="sessionTransacted" value="true"/>
    </bean>
This way JMS is Transaction control is performed when the message is monitored. When the listener fails to execute when receiving the message, JMS will roll back the received message. It should be noted here that access to other operations such as databases does not belong to the transaction control.

You can modify the code in JmsQueueReceiver to detect whether the transaction will be rolled back when sending an exception:


@Component("jmsQueueReceiver"









            {
                String text = textMessage.getText();
                System.out.println("######################["+text+"]##### #################");
                if(true)
                {
                    throw new RuntimeException("Error");
                }
            }
            catch (JMSException e)
            {
                e.printStackTrace();
            }
        }
    }
}
You can send a message to the Destination, and after processing it through the JmsQueueReceiver, send an exception and the transaction will roll over. You can view relevant information through http://10.10.195.187:8161/admin/queues.jsp (the ip address is the id of the blogger's ActiveMQ server, which can be modified according to the actual situation).

If you want to receive messages and database access in the same transaction, then we can configure an external transaction management and configure a message listener container (such as DefaultMessageListenerContainer) that supports external transaction management. To configure such a message monitoring container that participates in distributed transaction management, we can configure a JtaTransactionManager. Of course, the underlying JMS ConnectionFactory needs to be able to support distributed transaction management and correctly register our JtaTransactionManager. In this way, the message reception and the corresponding database access by the message listener will be under the control of the same database, and the transaction rollback operation will be performed when the message reception fails or the database access fails.


<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
       <property name="connectionFactory" ref="connectionFactory" />
       <property name="messageListener" ref="jmsQueueReceiver" />
       < property name="destination" ref="queueDestination" />
       <property name="sessionTransacted" value="true"/>
       <

   <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
When transactionManager is specified for the hour listener container, the message listener container will ignore the value of sessionTransacted.

The Spring+ActiveMQ integration has come to an end here, and all codes have been tested by bloggers to ensure effectiveness and correctness. If you have any questions, you can leave a message below.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326491094&siteId=291194637