The background of the project requires that you send an email notification to the user after changing the password. In order to prevent the program from blocking user operations during mail sending, the Chinese version used threads to send emails, but in the English version, I decided to use
JMS sends emails asynchronously, which further decouples the password change and email sending operations. Try JMS in the actual environment.
Our environment is spring 2.5, Tomcat 5.5, and activemq
Come
Implement JMS transmission and receiving.
First, we add activemq to spring.
Broker Configuration:
<Bean id = "broker"
Class = "org. Apache. activemq
. Xbean. brokerfactorybean ">
<Property name = "Config"
Value = "classpath: activemq
. Xml"
/>
<Property name = "start"
Value = "true"/>
</Bean>
We have configured brokerfactorybean here. This bean configures embedded brokers in spring and supports xbean configuration.
. The configuration file of the broker is specified by the config attribute. The configuration file is defined here as activemq in classpath.
. Xml.
Next we need to create the broker configuration file activemq
. Xml. In fact, we
You do not need to configure activemq from the beginning.
Jar package in org. Apache. activemq
In. xbean, there is an activemq
. XML,
We copy it to the WEB-INF/classes/directory and modify it.
The following is activemq.
. XML content:
<Beans>
<Bean
Class = "org. springframework. Beans. Factory. config. propertyplaceholderconfigurer"
/>
<Broker usejmx = "false"
Persistent = "false"
Xmlns = "http: // activemq
.Apache.org/schema/core ">
<Transportors ors>
<Transporturi uri = "TCP: // localhost: 61636"/>
</Transportors ors>
<Networkconnectors> </networkconnectors>
</Broker>
</Beans>
In the broker, we specify not to enable JMX and not to use persistence (persistent = "false ").
If messages are not stored persistently, after the container or JVM is closed, restarted, or crashed, all messages will be lost. In our business, we send a password change notification email and
It is not an important feature, so we choose not to use persistent storage, but for different business logic, we may need to perform persistent storage. Activemq
Submit
The persistent storage solution can store messages to file systems and databases.
To enable persistent storage in the broker, you must set persistent to true and persistenceadapter for its subnodes,
Configure journaledjdbc. Activemq
Activemq in the jar package
. XML has been commented out as an example. For details, refer.
Then we configure the JMS connection factory in spring.
<Bean id = "jmsfactory"
Class = "org. Apache. activemq
. Activemqconnectionfactory ">
<Property name = "brokerurl"
Value = "TCP: // localhost: 61636"/>
</Bean>
Note that the borkerurl should be in activemq
. Xml
The URI attribute of the transportctor node, which indicates the listening address of the JMS server.
Configure the message sending destination:
<Bean id = "topicdestination"
Class = "org. Apache. activemq
. Command. activemqtopic ">
<Constructor-Arg value = "My. Topic"/>
</Bean>
<Bean id = "queuedestination"
Class = "org. Apache. activemq
. Command. activemqqueue ">
<Constructor-Arg value = "My. queue"/>
</Bean>
In JMS, there are two types of destinations: topic and queue ). The difference between the two is that when a message is put into a topic destination, all subscribers
A notification will be received. For a queue, only one "subscriber" will receive the message. Once the message in the queue is processed, it will not exist in the queue. Obviously, for the mail sending program, using the queue is positive
If the subject is used, multiple identical emails may be sent.
Topic and queue are only different in JMS and their processing methods. For message senders and receivers, there is no difference in code.
Configure the JMS template for sending messages in Spring:
<Bean id = "producerjmstemplate"
Class = "org. springframework. JMS. Core. jmstemplate">
<Property name = "connectionfactory">
<Bean
Class = "org. springframework. JMS. Connection. singleconnectionfactory">
<Property name = "targetconnectionfactory"
Ref = "jmsfactory"/>
</Bean>
</Property>
<Property name = "defaultdestination"
Ref = "queuedestination"/>
<Property name = "messageconverter"
Ref = "usermessageconverter"/>
</Bean>
Note that defaultdestination here uses a queue-based destination.
User. username, user. Password, user. email,
User. fullname: It indicates that if we directly send the user object to the message queue, the user object can also be taken out during receiving, it is convenient to operate in the mail sending program.
Many, so in some cases, we define the messageconverter attribute, which specifies the message conversion Bean used for sending the message. In this way, the user is directly sent to the JMS queue.
Spring will automatically help us with the conversion. The following is the converter configuration and code:
<Bean id = "usermessageconverter"
Class = "com. tiandinet. JMS. sample. usermessageconverter"/>
This converter also converts received messages to user objects in message receiving.
Package COM. tiandinet. JMS. sample; <br/> Import javax. JMS. jmsexception; <br/> Import javax. JMS. message; <br/> Import javax. JMS. objectmessage; <br/> Import javax. JMS. session; <br/> Import Org. apache. activemq. command. activemqobjectmessage; <br/> Import Org. apache. commons. logging. log; <br/> Import Org. apache. commons. logging. logfactory; <br/> Import Org. springframework. JMS. support. converter. messageconverter; <br/> Import COM. tiandinet. JMS. sample. user; <br/>/** <br/> * converte user message. <br/> * @ author Yangtze <br/> */<br/> public class usermessageconverter implements messageconverter {<br/> Private Static transient log logger = logfactory. getlog (usermessageconverter. class); <br/>/** <br/> * {@ inheritdoc} <br/> * @ see Org. springframework. JMS. support. converter. messageconverter <br/> * # frommessage (javax. JMS. message) <br/> */<br/> Public object frommessage (message) throws jmsexception {<br/> If (logger. isdebugenabled () {<br/> logger. debug ("receive JMS message:" + message); <br/>}< br/> If (Message instanceof objectmessage) {<br/> objectmessage omsg = (objectmessage) message; <br/> If (omsg instanceof activemqobjectmessage) {<br/> activemqobjectmessage amsg = (activemqobjectmessage) omsg; <br/> try {<br/> User user = (User) amsg. getObject (); <br/> return user; <br/>} catch (exception e) {<br/> logger. error ("message: [" + message + "] is not a instance of user. "); <br/> throw new jmsexception (" message: ["+ message +"] is not a instance of user. "); <br/>}< br/>} else {<br/> logger. error ("message: [" + message + "] is not" <br/> + "a instance of activemqobjectmessage [user]. "); <br/> throw new jmsexception (" message: ["+ message +"] is not "<br/> +" a instance of activemqobjectmessage [user]. "); <br/>}< br/>} else {<br/> logger. error ("message: [" + message + "] is not a instance of objectmessage. "); <br/> throw new jmsexception (" message: ["+ message +"] is not a instance of objectmessage. "); <br/>}< br/>/** <br/> * {@ inheritdoc} <br/> * @ see Org. springframework. JMS. support. converter. messageconverter # tomessage (Java. lang. object, <br/> * javax. JMS. session) <br/> */<br/> public message tomessage (Object OBJ, session) throws jmsexception {<br/> If (logger. isdebugenabled () {<br/> logger. debug ("Convert user object to JMS message:" + OBJ); <br/>}< br/> If (OBJ instanceof user) {<br/> activemqobjectmessage MSG = (activemqobjectmessage) session. createobjectmessage (); <br/> MSG. setobject (User) OBJ); <br/> return MSG; <br/>} else {<br/> logger. error ("Object: [" + OBJ + "] is not a instance of user. "); <br/> throw new jmsexception (" Object: ["+ OBJ +"] is not a instance of user. "); <br/>}< br/>}
This program implements the messageconverter interface, and implements the frommessage and tomessage methods, respectively, to achieve the consumption of the received Conversion
And convert the user object to the message.
Activemqobjectmessage is used in the program. It is activemq.
Medium
An Implementation of javax. JMS. objectmessage.
At this point, we have completed the JMS connection factory and the JMS used to send the JMS message
Template configuration. Next, you should write the bean that sends the message. The Code is as follows:
Package COM. tiandinet. JMS. sample; <br/> Import Org. springframework. JMS. core. jmstemplate; <br/> Import COM. tiandinet. JMS. sample. user; <br/>/** <br/> * Send user's login information mail via JMS. <br/> * @ author Yangtze <br/> */<br/> public class usermessageproducerimpl implements iusermessageproducer {<br/> private jmstemplate; <br/>/** <br/> * {@ inheritdoc} <br/> * @ see COM. tiandinet. JMS. sample. iusermessageproducer <br/> * # senduserlogininformationmail (COM. tiandinet. JMS. sample. user) <br/> */<br/> Public void senduserlogininformationmail (User user) {<br/> getjmstemplate (). convertandsend (User); <br/>}< br/>/** <br/> * return the jmstemplate. <br/> * @ return the jmstemplate <br/> */<br/> Public final jmstemplate getjmstemplate () {<br/> return jmstemplate; <br/>}< br/>/** <br/> * set the jmstemplate. <br/> * @ Param jmstemplate <br/> * The jmstemplate to set <br/> */<br/> Public final void setjmstemplate (jmstemplate) {<br/> This. jmstemplate = jmstemplate; <br/>}< br/>}
The code is very simple. The senduserlogininformationmail method is the only one that we need to write.
In the convertandsend method, spring calls the previously configured converter to convert the user object we sent.
Configure this Java in spring and call it in controller to send the user object to JMS.
So far, we have enabled message sending, and now we can implement message receiving.
Compared with sending, the message receiving configuration is shorter. We use MDP (Message Drive
Pojo) to implement asynchronous message receiving. We need to implement the void onmessage (Message
To receive messages. However, we can use the messagelisteneradapter provided in spring to simplify the code for receiving messages.
Let's first write the interface and implementation class for message processing:
Package COM. tiandinet. JMS. sample; <br/> Import javax. JMS. jmsexception; <br/> Import javax. JMS. objectmessage; <br/> Import COM. tiandinet. JMS. sample. user; <br/>/** <br/> * JMS message handler. <br/> * Yangtze <br/> */<br/> Public interface imessageconsumer {<br/>/** <br/> * handle the user message. <br/> * @ Param user <br/> * User <br/> * @ throws jmsexception <br/> * exception <br/> */< br/> void handlemessage (User user) throws jmsexception; <br/>}< br/> package COM. tiandinet. JMS. sample; <br/> Import javax. JMS. jmsexception; <br/> Import Org. apache. commons. logging. log; <br/> Import Org. apache. commons. logging. logfactory; <br/> Import COM. tiandinet. JMS. sample. user; <br/> Import COM. tiandinet. JMS. sample. imailservice; <br/>/** <br/> * JMS message handler-for user message. <br/> * Yangtze <br/> */<br/> public class usermessageconsumerimpl implements imessageconsumer {<br/> Private Static transient log logger = logfactory. getlog (usermessageconsumerimpl. class); <br/> private imailservice mailservice; <br/>/** <br/> * {@ inheritdoc} <br/> * @ see COM. tiandinet. JMS. sample. imessageconsumer <br/> * # handlemessage (COM. tiandinet. JMS. sample. user) <br/> */<br/> Public void handlemessage (User user) throws jmsexception {<br/> If (logger. isdebugenabled () {<br/> logger. debug ("receive a user object from activemq:" + User. tostring (); <br/>}< br/> mailservice. senduserlogininformail (User); <br/>}< br/>}
Configure message listener
<Bean id = "messagelistener"
Class = "org. springframework. JMS. listener. Adapter. messagelisteneradapter">
<Constructor-Arg>
<Bean
Class = "com. tiandinet. JMS. sample. usermessageconsumerimpl">
<Property name = "mailservice"
Ref = "mailservice"/>
</Bean>
</Constructor>
<Property name = "defaultlistenermethod"
Value = "handlemessage"/>
<Property name = "messageconverter"
Ref = "usermessageconverter"/>
</Bean>
The mailservice is our mail sending class. Its senduserlogininformail method implements the mail sending function.
The defaultlistenermethod attribute of the message listening adapter specifies the method that spring calls after receiving the message.
Handlemessage. Spring calls the handlemessage (User user) method based on the user object of the received message.
Configure the message listening container and specify the defined message listener.
<Bean id = "listenercontainer"
Class = "org. springframework. JMS. listener. defaultmessagelistenercontainer">
<Property name = "concurrentconsumers"
Value = "5"/>
<Property name = "connectionfactory"
Ref = "jmsfactory"/>
<Property name = "destination"
Ref = "queuedestination"/>
<Property name = "messagelistener"
Ref = "messagelistener"/>
</Bean>