001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.jms.annotation; 018 019import java.lang.annotation.Documented; 020import java.lang.annotation.ElementType; 021import java.lang.annotation.Retention; 022import java.lang.annotation.RetentionPolicy; 023import java.lang.annotation.Target; 024 025import org.springframework.context.annotation.Import; 026 027/** 028 * Enable JMS listener annotated endpoints that are created under the cover 029 * by a {@link org.springframework.jms.config.JmsListenerContainerFactory 030 * JmsListenerContainerFactory}. To be used on 031 * {@link org.springframework.context.annotation.Configuration Configuration} 032 * classes as follows: 033 * 034 * <pre class="code"> 035 * @Configuration 036 * @EnableJms 037 * public class AppConfig { 038 * 039 * @Bean 040 * public DefaultJmsListenerContainerFactory myJmsListenerContainerFactory() { 041 * DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); 042 * factory.setConnectionFactory(connectionFactory()); 043 * factory.setDestinationResolver(destinationResolver()); 044 * factory.setSessionTransacted(true); 045 * factory.setConcurrency("5"); 046 * return factory; 047 * } 048 * 049 * // other @Bean definitions 050 * }</pre> 051 * 052 * The {@code JmsListenerContainerFactory} is responsible to create the listener container 053 * responsible for a particular endpoint. Typical implementations, as the 054 * {@link org.springframework.jms.config.DefaultJmsListenerContainerFactory DefaultJmsListenerContainerFactory} 055 * used in the sample above, provides the necessary configuration options that are supported by 056 * the underlying {@link org.springframework.jms.listener.MessageListenerContainer MessageListenerContainer}. 057 * 058 * <p>{@code @EnableJms} enables detection of {@link JmsListener} annotations on any 059 * Spring-managed bean in the container. For example, given a class {@code MyService}: 060 * 061 * <pre class="code"> 062 * package com.acme.foo; 063 * 064 * public class MyService { 065 * 066 * @JmsListener(containerFactory = "myJmsListenerContainerFactory", destination="myQueue") 067 * public void process(String msg) { 068 * // process incoming message 069 * } 070 * }</pre> 071 * 072 * The container factory to use is identified by the {@link JmsListener#containerFactory() containerFactory} 073 * attribute defining the name of the {@code JmsListenerContainerFactory} bean to use. When none 074 * is set a {@code JmsListenerContainerFactory} bean with name {@code jmsListenerContainerFactory} is 075 * assumed to be present. 076 * 077 * <p>the following configuration would ensure that every time a {@link javax.jms.Message} 078 * is received on the {@link javax.jms.Destination} named "myQueue", {@code MyService.process()} 079 * is called with the content of the message: 080 * 081 * <pre class="code"> 082 * @Configuration 083 * @EnableJms 084 * public class AppConfig { 085 * 086 * @Bean 087 * public MyService myService() { 088 * return new MyService(); 089 * } 090 * 091 * // JMS infrastructure setup 092 * }</pre> 093 * 094 * Alternatively, if {@code MyService} were annotated with {@code @Component}, the 095 * following configuration would ensure that its {@code @JmsListener} annotated 096 * method is invoked with a matching incoming message: 097 * 098 * <pre class="code"> 099 * @Configuration 100 * @EnableJms 101 * @ComponentScan(basePackages="com.acme.foo") 102 * public class AppConfig { 103 * }</pre> 104 * 105 * Note that the created containers are not registered against the application context 106 * but can be easily located for management purposes using the 107 * {@link org.springframework.jms.config.JmsListenerEndpointRegistry JmsListenerEndpointRegistry}. 108 * 109 * <p>Annotated methods can use flexible signature; in particular, it is possible to use 110 * the {@link org.springframework.messaging.Message Message} abstraction and related annotations, 111 * see {@link JmsListener} Javadoc for more details. For instance, the following would 112 * inject the content of the message and a custom "myCounter" JMS header: 113 * 114 * <pre class="code"> 115 * @JmsListener(containerFactory = "myJmsListenerContainerFactory", destination="myQueue") 116 * public void process(String msg, @Header("myCounter") int counter) { 117 * // process incoming message 118 * }</pre> 119 * 120 * These features are abstracted by the {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory} 121 * that is responsible to build the necessary invoker to process the annotated method. By default, 122 * {@link org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory} is used. 123 * 124 * <p>When more control is desired, a {@code @Configuration} class may implement 125 * {@link JmsListenerConfigurer}. This allows access to the underlying 126 * {@link org.springframework.jms.config.JmsListenerEndpointRegistrar JmsListenerEndpointRegistrar} 127 * instance. The following example demonstrates how to specify an explicit default 128 * {@code JmsListenerContainerFactory} 129 * 130 * <pre class="code"> 131 * @Configuration 132 * @EnableJms 133 * public class AppConfig implements JmsListenerConfigurer { 134 * 135 * @Override 136 * public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { 137 * registrar.setContainerFactory(myJmsListenerContainerFactory()); 138 * } 139 * 140 * @Bean 141 * public JmsListenerContainerFactory<?> myJmsListenerContainerFactory() { 142 * // factory settings 143 * } 144 * 145 * @Bean 146 * public MyService myService() { 147 * return new MyService(); 148 * } 149 * }</pre> 150 * 151 * For reference, the example above can be compared to the following Spring XML 152 * configuration: 153 * 154 * <pre class="code"> 155 * {@code <beans> 156 * 157 * <jms:annotation-driven container-factory="myJmsListenerContainerFactory"/> 158 * 159 * <bean id="myJmsListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory"> 160 * // factory settings 161 * </bean> 162 * 163 * <bean id="myService" class="com.acme.foo.MyService"/> 164 * 165 * </beans> 166 * }</pre> 167 * 168 * It is also possible to specify a custom {@link org.springframework.jms.config.JmsListenerEndpointRegistry 169 * JmsListenerEndpointRegistry} in case you need more control on the way the containers 170 * are created and managed. The example below also demonstrates how to customize the 171 * {@code JmsHandlerMethodFactory} to use with a custom {@link org.springframework.validation.Validator 172 * Validator} so that payloads annotated with {@link org.springframework.validation.annotation.Validated 173 * Validated} are first validated against a custom {@code Validator}. 174 * 175 * <pre class="code"> 176 * @Configuration 177 * @EnableJms 178 * public class AppConfig implements JmsListenerConfigurer { 179 * 180 * @Override 181 * public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { 182 * registrar.setEndpointRegistry(myJmsListenerEndpointRegistry()); 183 * registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory); 184 * } 185 * 186 * @Bean 187 * public JmsListenerEndpointRegistry<?> myJmsListenerEndpointRegistry() { 188 * // registry configuration 189 * } 190 * 191 * @Bean 192 * public JmsHandlerMethodFactory myJmsHandlerMethodFactory() { 193 * DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory(); 194 * factory.setValidator(new MyValidator()); 195 * return factory; 196 * } 197 * 198 * @Bean 199 * public MyService myService() { 200 * return new MyService(); 201 * } 202 * }</pre> 203 * 204 * For reference, the example above can be compared to the following Spring XML 205 * configuration: 206 * <pre class="code"> 207 * {@code <beans> 208 * 209 * <jms:annotation-driven registry="myJmsListenerEndpointRegistry" 210 * handler-method-factory="myJmsHandlerMethodFactory"/> 211 * 212 * <bean id="myJmsListenerEndpointRegistry" 213 * class="org.springframework.jms.config.JmsListenerEndpointRegistry"> 214 * // registry configuration 215 * </bean> 216 * 217 * <bean id="myJmsHandlerMethodFactory" 218 * class="org.springframework.messaging.handler.support.DefaultJmsHandlerMethodFactory"> 219 * <property name="validator" ref="myValidator"/> 220 * </bean> 221 * 222 * <bean id="myService" class="com.acme.foo.MyService"/> 223 * 224 * </beans> 225 * }</pre> 226 * 227 * Implementing {@code JmsListenerConfigurer} also allows for fine-grained 228 * control over endpoints registration via the {@code JmsListenerEndpointRegistrar}. 229 * For example, the following configures an extra endpoint: 230 * 231 * <pre class="code"> 232 * @Configuration 233 * @EnableJms 234 * public class AppConfig implements JmsListenerConfigurer { 235 * 236 * @Override 237 * public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { 238 * SimpleJmsListenerEndpoint myEndpoint = new SimpleJmsListenerEndpoint(); 239 * // ... configure the endpoint 240 * registrar.registerEndpoint(endpoint, anotherJmsListenerContainerFactory()); 241 * } 242 * 243 * @Bean 244 * public MyService myService() { 245 * return new MyService(); 246 * } 247 * 248 * @Bean 249 * public JmsListenerContainerFactory<?> anotherJmsListenerContainerFactory() { 250 * // ... 251 * } 252 * 253 * // JMS infrastructure setup 254 * }</pre> 255 * 256 * Note that all beans implementing {@code JmsListenerConfigurer} will be detected and 257 * invoked in a similar fashion. The example above can be translated in a regular bean 258 * definition registered in the context in case you use the XML configuration. 259 * 260 * @author Stephane Nicoll 261 * @since 4.1 262 * @see JmsListener 263 * @see JmsListenerAnnotationBeanPostProcessor 264 * @see org.springframework.jms.config.JmsListenerEndpointRegistrar 265 * @see org.springframework.jms.config.JmsListenerEndpointRegistry 266 */ 267@Target(ElementType.TYPE) 268@Retention(RetentionPolicy.RUNTIME) 269@Documented 270@Import(JmsBootstrapConfiguration.class) 271public @interface EnableJms { 272}