this is my first time with Spring JMS (and with JMS in general) and I have some doubts related the concept of the JmsTemplate callback.
I know that the JmsTemplate is a class provided from Spring to:
and that it is used for message production and synchronous message reception. It simplifies the use of JMS since it handles the creation and release of resources when sending or synchronously receiving messages.
Reading the Spring official documentation (here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html) I found:
Code that uses the JmsTemplate only needs to implement callback interfaces giving them a clearly defined high level contract. The MessageCreator callback interface creates a message given a Session provided by the calling code in JmsTemplate.
This is not clear for me. What exactly are these callback?
At the beginning I thought that a callback are a method provided from the JmsTemplate but reading here it seems something more similar to an interface that I have to implement. How it works?
I also found this example:
SENDING A POJO THROUGHT JMS (using the JmsTemplate):
public class JmsOrderManager implements OrderManager {
@Autowired JmsTemplate jmsTemplate;
@Autowired Destination orderQueue;
public void placeOrder(Order order) {
String stringMessage = "New order " + order.getNumber();
jmsTemplate.convertAndSend("messageQueue", stringMessage );
// use destination resolver and message converter
jmsTemplate.convertAndSend(orderQueue, order); // use message converter
jmsTemplate.convertAndSend(order); // use converter and default destination
}
}
I thought that the convertAndSend() method is a JmsTemplate callback but probably this assertion is not correct.
Can you explain me what exactly is a JmsTemplate callback?
The design principle common to Spring template classes is to provide helper methods to perform common operations and for more sophisticated usage, delegate the essence of the processing task to user implemented callback interfaces.
In JMS Connection will be obtained from a factory
=> From that connection session is created, a seesion is a unit of work, it also provides transaction
=> from session you create different types of JMS Message like TextMessage, ObjectMessage, MapMessage, BytesMessage and StreamMessage in following ways session.createTextMessage("hello queue world"); session.createObjectMessage(someSerializedObject) and so on
=> The same session is also responsible for creating instance of MessageProducer session.createProducer(destination) and MessageConsumer session.createConsumer(destination)
You have following convertAndSend possibilities (Overloaded methods):
jmsTemplate.convertAndSend(message)
jmsTemplate.convertAndSend(destination, message)
jmsTemplate.convertAndSend(message, postProcessor)
jmsTemplate.convertAndSend(destinationName, message)
jmsTemplate.convertAndSend(destination, message, postProcessor)
jmsTemplate.convertAndSend(destinationName, message, postProcessor)
What is happening? The basic use of callback like 3rd 5th and 6th signature is you can change the message after being converting the object to a JMS message through a configured MessageConverter. You are seeing an actual destination to be resolved by a DestinationResolver in case of 6th, you are not passing it, it will be resolved from JNDI, if it is registered there.
What does it mean?
jmsTemplate.send(this.queue, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("hello queue world");
}
});
Here in this example you are seeing with send() method of JMS template you are providing anonymous implemetation(callback) where the method gives you access to to Session Object and from that session you created customized session.createTextMessage("hello queue world") message.
Same way in convertAndSend(you can get access to postprocessors to modify)
public void ConvertSend() {
Map map = new HashMap();
map.put("Name", "Vimal");
map.put("Age", new Integer(45));
jmsTemplate.convertAndSend("jmsQueue", map, new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
message.setIntProperty("ID", 9999);
message.setJMSCorrelationID("123-99999");
return message;
}
});
}
Message Object was created but you are modifying it(adding two more properties, in addition to name and age). The MessagePostProcessor interface gives you access to the message after it has been converted, but before it is sent.
In other words! setting of message properties, headers and body can't be encapsulated inside a converter class(SimpleMessageConverter), but the MessagePostProcessor Interface gives you access to the message after it has been converted, but before sent.