In J2EE world JMS was often used for asynchronous execution of synchronous methods. There was no other way to invoke session beans in a background thread. EJB 3.1 introduced an easy way to solve background execution without using messaging.
It is sufficient to declare methods as @Asynchronous and they will be invoked in background thread. The result value of an asynchronous invocation is available to the client by returning the Future
The built-in support for asynchronous processing is easier and cleaner compared to the JMS way and it also allows bidirectional communication. Implementing request-response communication with JMS messaging is harder and you would need input queue and output queue. JMS on the other hand allows looser coupling.
So, say for example that you want to send email asynchronously (example assumes that glassfish application server is used).
Using JMS you can do it in combination with message driven beans (components designed to consume the asynchronous messages). As soon as a new message reaches the jms destination, an message driven bean instance is retrieved from the pool to handle the message.
To use JMS and message driven beans you have to first configure JMS connection factory and destination queue through glassfish administration console. For example:
Calling client (JSF bean or another EJB for example) then can inject these resources and use them to send message (queue asynchronous task).
//inject connection factory and destination @Resource(name="connFactory", mappedName="mailConnFactory") private QueueConnectionFactory qFactory; @Resource(name="jmsQueue", mappedName="mailQueue") private Queue queue;
And asynchronous call is done by sending message that will be asynchronously processed by message driven bean.
QueueConnection qConn = (QueueConnection)qFactory. createConnection(); // Get session Session session = qConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); // Create the JMS message ObjectMessage msg = session.createObjectMessage(); // set payload MailData data = new MailData("reciever@mail.com","message text"); msg.setObject(data); // Send JMS message session.createProducer(queue).send(msg); //release resources session.close(); qConn.close();
Once message is queued you need message driven bean that will process message. In this case this message driven bean will send actual email. Mail session resource in glassfish administration console(under resources/java mail sessions node) must be configured to send actual email.
@MessageDriven(mappedName="mailQueue") public class MailSenderBean implements MessageListener { @Resource(name = "mail" ) private Session mailSession; @Override public void onMessage(Message message) { if (message instanceof ObjectMessage) { try{ ObjectMessage msg = (ObjectMessage)message; MailData data = (MailData)msg.getObject(); MimeMessage msg = new MimeMessage(mailSession); msg.setSubject("subject"); msg.setRecipient(RecipientType.TO, new InternetAddress(data.getRecipient())); msg.setContent(data.getText(), "text/html"); Transport.send(msg); }catch(Exception e) { // handle exception } } } }
And to accomplish same thing with built in asynchronous support you just have to annotate session bean method with @Asynchronous annotation and container will execute method in background thread.
@Stateless public class MailSenderBean implements MailSender { @Resource(name = "mail" ) private Session mailSession; @Asynchronous @Override public void sendEmail(MailData data){ try { MimeMessage msg = new MimeMessage(mailSession); msg.setSubject("subject"); msg.setRecipient(RecipientType.TO, new InternetAddress(data.getRecipient())); msg.setContent(data.getText(), "text/html"); Transport.send(msg); } catch (Exception e) { //handle error } } }
This method could also return Future