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 * &#064;Configuration
036 * &#064;EnableJms
037 * public class AppConfig {
038 *
039 *     &#064;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 &#064;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 *     &#064;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 * &#064;Configuration
083 * &#064;EnableJms
084 * public class AppConfig {
085 *
086 *     &#064;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 * &#064;Configuration
100 * &#064;EnableJms
101 * &#064;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 * &#064;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 * &#064;Configuration
132 * &#064;EnableJms
133 * public class AppConfig implements JmsListenerConfigurer {
134 *
135 *     &#064;Override
136 *     public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
137 *         registrar.setContainerFactory(myJmsListenerContainerFactory());
138 *     }
139 *
140 *     &#064;Bean
141 *     public JmsListenerContainerFactory<?> myJmsListenerContainerFactory() {
142 *         // factory settings
143 *     }
144 *
145 *     &#064;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 * &#064;Configuration
177 * &#064;EnableJms
178 * public class AppConfig implements JmsListenerConfigurer {
179 *
180 *     &#064;Override
181 *     public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
182 *         registrar.setEndpointRegistry(myJmsListenerEndpointRegistry());
183 *         registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory);
184 *     }
185 *
186 *     &#064;Bean
187 *     public JmsListenerEndpointRegistry<?> myJmsListenerEndpointRegistry() {
188 *         // registry configuration
189 *     }
190 *
191 *     &#064;Bean
192 *     public JmsHandlerMethodFactory myJmsHandlerMethodFactory() {
193 *        DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
194 *        factory.setValidator(new MyValidator());
195 *        return factory;
196 *     }
197 *
198 *     &#064;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"/&gt;
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 * &#064;Configuration
233 * &#064;EnableJms
234 * public class AppConfig implements JmsListenerConfigurer {
235 *
236 *     &#064;Override
237 *     public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
238 *         SimpleJmsListenerEndpoint myEndpoint = new SimpleJmsListenerEndpoint();
239 *         // ... configure the endpoint
240 *         registrar.registerEndpoint(endpoint, anotherJmsListenerContainerFactory());
241 *     }
242 *
243 *     &#064;Bean
244 *     public MyService myService() {
245 *         return new MyService();
246 *     }
247 *
248 *     &#064;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}