JMS (Java Messaging Service) is always a much orated topic, because of its applicability, expediency, and implementation in diverse plots.
I thought of exploring JMS again ,but after adding a different flavour to it. Confused Hmmmm!!!!
The flavour is of Spring and Grails 3 i.e. using Spring JMS in Grails framework.
Spring really has made JMS easy to implement.
I have Queues and Topics using APACHE ACTIVE MQ 5.13.3.
The source code is available at GITHUB
The Objective being very simple:
1) A message will be sent to a Queue/Topic (Using JMSTemplate).
2) A Listener implementation listening to particular destinations. [Please note: Since the intention was to receive messages asynchronously so we have tried with Listener here rather than receiving it through JMS Template ]
    a) Listener implementation is done using following ways:
        Registered bean in the Spring Applicaion Context using Message Listener Adapter.
        Registered bean in the Spring Applicaion Context by implementing MessageListener interface.
        Annotating registered beans in the application context.
    Will discussing each of the implementations configuration wise.
3) Applying Message Converters in order to transfrom Messages To/From custom types.
4) Integrating Message Validators with the Listener.
Will be discussing each of the implementations configuration wise along with some custom configuration for more added flexibility to the whole framework.
Grails does provide a jms plugin and that is really cool.
With a registered bean (using static exposes = ['jms'] in the Bean class) in the application context we can annotate a method with @Queue/@Subscriber specifying the destination name within the annotation like @Subscriber(topic = "topic.name") and @Queue(name='queue.name') and that method starts listening to that destination.
However for sending messages, Grails JMS plugin includes a bean jmsService. We can use the bean to send messages like the following:
However in the documentation of the plugin custom configuration options are there, but I personally found it difficult to configure them in Grails 3.
So I resort to Spring JMS.
Lets get back to action:
Added following dependencies in build.gradle
Grails automatically injects the bean of the same type when we decalare a bean with the same name as in configuration.
So in while declaring:
Now lets go to Listener section:
Here we have implemented Message Listener with the help of MessageListenerAdapter, and has also mentioned the default listener method, which will handle message processing.
We then need to register this Listner with the Listener Container Factory specifying the destination and the transaction manager.
As:
As:
Next we have implemented an annotated Listener.
For this annotated listener, I have defined a separate Java based configuration apart from resources.groovy and defined all the beans there.
The class has been named as AMQPConfiguration.
We have injected jmsConnectionFactory, which is the bean as defined in resources.groovy , and is needed for creating MessageListenerContainerFactory.
Ok lets come to it step by step.
We have a Listener class named AMQPMessageListener. We have annotated its method with @JmsListener by specifying the destination it will listen to and also the conainerFactory, that we have configured in the previous step. We can define multiple methods and annotate each method with a separate destinate that it will listen to.
Now in order to tell Spring that this is the Listener class, we have defined a bean of this class in the Java based configuration AMQPConfiguration and annotated the configuration class with the @EnableJMS, this annotation scans the beans defined in this context for Listener registration by looking up for methods annotated with @JmsListener.
The configuration looks like:
So @EnableJMS also created JMSListener Container and from the jmsListenerContainerFactory bean that we have defined and bridge the destination and the listener.
The imeplentation of JmsListenerConfigurer provides more control to the whole setup because it helps us override the method configureJmsListeners(), which takes JmsListenerEndpointRegistrar as a parameter.
JmsListenerEndpointRegistrar is used for registration of JmsListenerEndpointRegistry, with the help of which we can define programmatically endpoint/listener. Here we have not implemented JmsListenerEndpointRegistry. We have used JmsListenerEndpointRegistrar to register containerFactory along with messaheHandlerMethodFactory, which the contains the MessageValidators and the MessageConverters at the Listener end.
I thought of exploring JMS again ,but after adding a different flavour to it. Confused Hmmmm!!!!
The flavour is of Spring and Grails 3 i.e. using Spring JMS in Grails framework.
Spring really has made JMS easy to implement.
I have Queues and Topics using APACHE ACTIVE MQ 5.13.3.
The source code is available at GITHUB
The Objective being very simple:
1) A message will be sent to a Queue/Topic (Using JMSTemplate).
2) A Listener implementation listening to particular destinations. [Please note: Since the intention was to receive messages asynchronously so we have tried with Listener here rather than receiving it through JMS Template ]
    a) Listener implementation is done using following ways:
        Registered bean in the Spring Applicaion Context using Message Listener Adapter.
        Registered bean in the Spring Applicaion Context by implementing MessageListener interface.
        Annotating registered beans in the application context.
    Will discussing each of the implementations configuration wise.
3) Applying Message Converters in order to transfrom Messages To/From custom types.
4) Integrating Message Validators with the Listener.
Will be discussing each of the implementations configuration wise along with some custom configuration for more added flexibility to the whole framework.
Grails does provide a jms plugin and that is really cool.
With a registered bean (using static exposes = ['jms'] in the Bean class) in the application context we can annotate a method with @Queue/@Subscriber specifying the destination name within the annotation like @Subscriber(topic = "topic.name") and @Queue(name='queue.name') and that method starts listening to that destination.
However for sending messages, Grails JMS plugin includes a bean jmsService. We can use the bean to send messages like the following:
def jmsService jmsService.send(queue:"mic1.queue","First Message") jmsService.send(topic:"mic.topic","Broadcast Message")So using named propperty (queue/topic) we can specify the destination. That's flexible!!!
However in the documentation of the plugin custom configuration options are there, but I personally found it difficult to configure them in Grails 3.
So I resort to Spring JMS.
Lets get back to action:
Added following dependencies in build.gradle
compile "org.springframework:spring-jms:4.2.0.RELEASE" compile "org.apache.activemq:activemq-core:5.7.0"For sending messages to the destination:
jmsTemplate.convertAndSend "mic1.queue","FirstMessage With Template" jmsTemplate.convertAndSend "mic2.queue","FirstMessage With Template For Annotated Listener"jmsTemplate is configured in resources.groovy as:
jmsConnectionFactory(ActiveMQConnectionFactory) {
brokerURL = 'tcp://localhost:61616'
}
customMessageConverter2(CustomMessageConverter2)
jmsTemplate(JmsTemplate) {
connectionFactory = jmsConnectionFactory
messageConverter = customMessageConverter2
}
jmsConnectionFactory makes establishes connection with the broker and customMessageConverter2 is used for Message transformation as siad before.
both the beans are used in configuring jmsTemplate.Grails automatically injects the bean of the same type when we decalare a bean with the same name as in configuration.
So in while declaring:
JmsTemplate jmsTemplatein the controller, we have not used any @Autowired annotation. Grails does that auto injection, as Grails follows CoC (Convention over Configuration) principle. Cool isn't it.
Now lets go to Listener section:
Here we have implemented Message Listener with the help of MessageListenerAdapter, and has also mentioned the default listener method, which will handle message processing.
We then need to register this Listner with the Listener Container Factory specifying the destination and the transaction manager.
As:
messageListener(MessageListenerAdapter, ref("messageDelegateService")) {
defaultListenerMethod = "receive"
}
jmsContainerQueue(DefaultMessageListenerContainer) {
connectionFactory = jmsConnectionFactory
destinationName = "mic1.queue"
messageListener = messageListener//ref("messageConsumerJMSService")
transactionManager = transactionManager
//autoStartup = false
}
The bean i.e. messageDelegateService, that we have used here implements an interface. We can also register a any class which do not implement interface.As:
messageListenerTopic(MessageListenerAdapter, ref("messageConsumerService")) {
defaultListenerMethod = "interceptMessage3"
}
jmsContainerTopic2(DefaultMessageListenerContainer) {
connectionFactory = jmsConnectionFactory
destinationName = "mic.topic"
messageListener = messageListenerTopic//ref("messageConsumerJMSService")
transactionManager = transactionManager
//autoStartup = false
}
This part is committed in my code base as I have not implemented topic. The source code can be look up at GITHUBNext we have implemented an annotated Listener.
For this annotated listener, I have defined a separate Java based configuration apart from resources.groovy and defined all the beans there.
The class has been named as AMQPConfiguration.
We have injected jmsConnectionFactory, which is the bean as defined in resources.groovy , and is needed for creating MessageListenerContainerFactory.
Ok lets come to it step by step.
We have a Listener class named AMQPMessageListener. We have annotated its method with @JmsListener by specifying the destination it will listen to and also the conainerFactory, that we have configured in the previous step. We can define multiple methods and annotate each method with a separate destinate that it will listen to.
Now in order to tell Spring that this is the Listener class, we have defined a bean of this class in the Java based configuration AMQPConfiguration and annotated the configuration class with the @EnableJMS, this annotation scans the beans defined in this context for Listener registration by looking up for methods annotated with @JmsListener.
The configuration looks like:
@Configuration
@EnableJms
public class AMQPConfiguration implements JmsListenerConfigurer {
@Autowired
ActiveMQConnectionFactory jmsConnectionFactory
.........
@Bean
public AMQPMessageListener amqpMessageListener() {
return new AMQPMessageListener()
}
.........
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(jmsConnectionFactory);
//factory.setDestinationResolver(destinationResolver());
factory.setConcurrency("3-10");
return factory;
}
.............
}
Now why we have implemented JmsListenerConfigurer in the configuration class, I will get back to it.So @EnableJMS also created JMSListener Container and from the jmsListenerContainerFactory bean that we have defined and bridge the destination and the listener.
The imeplentation of JmsListenerConfigurer provides more control to the whole setup because it helps us override the method configureJmsListeners(), which takes JmsListenerEndpointRegistrar as a parameter.
JmsListenerEndpointRegistrar is used for registration of JmsListenerEndpointRegistry, with the help of which we can define programmatically endpoint/listener. Here we have not implemented JmsListenerEndpointRegistry. We have used JmsListenerEndpointRegistrar to register containerFactory along with messaheHandlerMethodFactory, which the contains the MessageValidators and the MessageConverters at the Listener end.
