Annotation Interface EnableJms


Enable JMS listener annotated endpoints that are created under the cover by a JmsListenerContainerFactory. To be used on @Configuration classes as follows:
@Configuration
@EnableJms
public class AppConfig {

    @Bean
    public DefaultJmsListenerContainerFactory myJmsListenerContainerFactory() {
      DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
      factory.setConnectionFactory(connectionFactory());
      factory.setDestinationResolver(destinationResolver());
      factory.setSessionTransacted(true);
      factory.setConcurrency("5");
      return factory;
    }

    // other @Bean definitions
}

The JmsListenerContainerFactory is responsible for creating the listener container responsible for a particular endpoint. Typical implementations, as the DefaultJmsListenerContainerFactory used in the sample above, provide the necessary configuration options that are supported by the underlying MessageListenerContainer.

@EnableJms enables detection of @JmsListener annotations on any Spring-managed bean in the container. For example, given a class MyService:

package com.acme.foo;

public class MyService {

    @JmsListener(containerFactory = "myJmsListenerContainerFactory", destination="myQueue")
    public void process(String msg) {
        // process incoming message
    }
}

The container factory to use is identified by the containerFactory attribute defining the name of the JmsListenerContainerFactory bean to use. When none is set a JmsListenerContainerFactory bean with name jmsListenerContainerFactory is assumed to be present.

The following configuration would ensure that every time a Message is received on the Destination named "myQueue", MyService.process() is invoked with the content of the message:

@Configuration
@EnableJms
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }

    // JMS infrastructure setup
}

Alternatively, if MyService were annotated with @Component, the following configuration would ensure that its @JmsListener annotated method is invoked with a matching incoming message:

@Configuration
@EnableJms
@ComponentScan(basePackages="com.acme.foo")
public class AppConfig {
}

Note that the created containers are not registered against the application context but can be easily located for management purposes using the JmsListenerEndpointRegistry.

Annotated methods can use flexible signature; in particular, it is possible to use the Message abstraction and related annotations, see JmsListener Javadoc for more details. For instance, the following would inject the content of the message and a custom "myCounter" JMS header:

@JmsListener(containerFactory = "myJmsListenerContainerFactory", destination="myQueue")
public void process(String msg, @Header("myCounter") int counter) {
    // process incoming message
}

These features are abstracted by the MessageHandlerMethodFactory that is responsible for building the necessary invoker to process the annotated method. By default, DefaultMessageHandlerMethodFactory is used.

When more control is desired, a @Configuration class may implement JmsListenerConfigurer. This allows access to the underlying JmsListenerEndpointRegistrar instance. The following example demonstrates how to specify an explicit default JmsListenerContainerFactory

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
        registrar.setContainerFactory(myJmsListenerContainerFactory());
    }

    @Bean
    public JmsListenerContainerFactory<?> myJmsListenerContainerFactory() {
        // factory settings
    }

    @Bean
    public MyService myService() {
        return new MyService();
    }
}
For reference, the example above can be compared to the following Spring XML configuration:
<beans>

    <jms:annotation-driven container-factory="myJmsListenerContainerFactory"/>

    <bean id="myJmsListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
          // factory settings
    </bean>

    <bean id="myService" class="com.acme.foo.MyService"/>

</beans>
}

It is also possible to specify a custom JmsListenerEndpointRegistry in case you need more control over the way the containers are created and managed. The example below also demonstrates how to customize the JmsHandlerMethodFactory to use with a custom Validator so that payloads annotated with Validated are first validated against a custom Validator.

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
        registrar.setEndpointRegistry(myJmsListenerEndpointRegistry());
        registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory);
    }

    @Bean
    public JmsListenerEndpointRegistry<?> myJmsListenerEndpointRegistry() {
        // registry configuration
    }

    @Bean
    public JmsHandlerMethodFactory myJmsHandlerMethodFactory() {
       DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
       factory.setValidator(new MyValidator());
       return factory;
    }

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

For reference, the example above can be compared to the following Spring XML configuration:

<beans>

    <jms:annotation-driven registry="myJmsListenerEndpointRegistry"
        handler-method-factory="myJmsHandlerMethodFactory"/>

    <bean id="myJmsListenerEndpointRegistry"
          class="org.springframework.jms.config.JmsListenerEndpointRegistry">
          // registry configuration
    </bean>

    <bean id="myJmsHandlerMethodFactory"
          class="org.springframework.messaging.handler.support.DefaultJmsHandlerMethodFactory">
        <property name="validator" ref="myValidator"/>
    </bean>

    <bean id="myService" class="com.acme.foo.MyService"/>

</beans>

Implementing JmsListenerConfigurer also allows for fine-grained control over endpoint registration via the JmsListenerEndpointRegistrar. For example, the following configures an extra endpoint:

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
        SimpleJmsListenerEndpoint myEndpoint = new SimpleJmsListenerEndpoint();
        // ... configure the endpoint
        registrar.registerEndpoint(endpoint, anotherJmsListenerContainerFactory());
    }

    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public JmsListenerContainerFactory<?> anotherJmsListenerContainerFactory() {
        // ...
    }

    // JMS infrastructure setup
}

Note that all beans implementing JmsListenerConfigurer will be detected and invoked in a similar fashion. The example above can be translated into a regular bean definition registered in the context in case you use the XML configuration.

Since:
4.1
Author:
Stephane Nicoll
See Also: