提交 92c657e1 编写于 作者: J Juergen Hoeller

JmsListener/ScheduledAnnotationBeanPostProcessor uses...

JmsListener/ScheduledAnnotationBeanPostProcessor uses SmartInitializingSingleton instead of ContextRefreshedEvent

Also reducing the container dependencies to BeanFactory instead of ApplicationContext, wherever possible.

Issue: SPR-12039
上级 b6389a6c
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -23,13 +23,14 @@ import java.util.TimeZone;
import java.util.concurrent.ScheduledExecutorService;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.TaskScheduler;
......@@ -57,7 +58,7 @@ import org.springframework.util.StringValueResolver;
* <p>Auto-detects any {@link SchedulingConfigurer} instances in the container,
* allowing for customization of the scheduler to be used or for fine-grained control
* over task registration (e.g. registration of {@link Trigger} tasks.
* See @{@link EnableScheduling} Javadoc for complete usage details.
* See the @{@link EnableScheduling} javadocs for complete usage details.
*
* @author Mark Fisher
* @author Juergen Hoeller
......@@ -70,18 +71,23 @@ import org.springframework.util.StringValueResolver;
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
*/
public class ScheduledAnnotationBeanPostProcessor
implements BeanPostProcessor, Ordered, EmbeddedValueResolverAware, ApplicationContextAware,
ApplicationListener<ContextRefreshedEvent>, DisposableBean {
implements BeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanFactoryAware,
SmartInitializingSingleton, DisposableBean {
private Object scheduler;
private StringValueResolver embeddedValueResolver;
private ApplicationContext applicationContext;
private ListableBeanFactory beanFactory;
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
}
/**
* Set the {@link org.springframework.scheduling.TaskScheduler} that will invoke
* the scheduled methods, or a {@link java.util.concurrent.ScheduledExecutorService}
......@@ -96,16 +102,63 @@ public class ScheduledAnnotationBeanPostProcessor
this.embeddedValueResolver = resolver;
}
/**
* Making a {@link BeanFactory} available is optional; if not set,
* {@link SchedulingConfigurer} beans won't get autodetected and
* a {@link #setScheduler scheduler} has to be explicitly configured.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (beanFactory instanceof ListableBeanFactory ? (ListableBeanFactory) beanFactory : null);
}
/**
* @deprecated as of Spring 4.1, in favor of {@link #setBeanFactory}
*/
@Deprecated
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.beanFactory = applicationContext;
}
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
public void afterSingletonsInstantiated() {
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
if (this.beanFactory != null) {
Map<String, SchedulingConfigurer> configurers = this.beanFactory.getBeansOfType(SchedulingConfigurer.class);
for (SchedulingConfigurer configurer : configurers.values()) {
configurer.configureTasks(this.registrar);
}
}
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
schedulers.putAll(this.beanFactory.getBeansOfType(TaskScheduler.class));
schedulers.putAll(this.beanFactory.getBeansOfType(ScheduledExecutorService.class));
if (schedulers.size() == 0) {
// do nothing -> fall back to default scheduler
}
else if (schedulers.size() == 1) {
this.registrar.setScheduler(schedulers.values().iterator().next());
}
else if (schedulers.size() >= 2){
throw new IllegalStateException(
"More than one TaskScheduler and/or ScheduledExecutorService " +
"exist within the context. Remove all but one of the beans; or " +
"implement the SchedulingConfigurer interface and call " +
"ScheduledTaskRegistrar#setScheduler explicitly within the " +
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
}
}
this.registrar.afterPropertiesSet();
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
......@@ -254,44 +307,6 @@ public class ScheduledAnnotationBeanPostProcessor
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() != this.applicationContext) {
return;
}
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
Map<String, SchedulingConfigurer> configurers =
this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
for (SchedulingConfigurer configurer : configurers.values()) {
configurer.configureTasks(this.registrar);
}
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
schedulers.putAll(this.applicationContext.getBeansOfType(TaskScheduler.class));
schedulers.putAll(this.applicationContext.getBeansOfType(ScheduledExecutorService.class));
if (schedulers.size() == 0) {
// do nothing -> fall back to default scheduler
}
else if (schedulers.size() == 1) {
this.registrar.setScheduler(schedulers.values().iterator().next());
}
else if (schedulers.size() >= 2){
throw new IllegalStateException(
"More than one TaskScheduler and/or ScheduledExecutorService " +
"exist within the context. Remove all but one of the beans; or " +
"implement the SchedulingConfigurer interface and call " +
"ScheduledTaskRegistrar#setScheduler explicitly within the " +
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
}
}
this.registrar.afterPropertiesSet();
}
@Override
public void destroy() {
......
......@@ -22,14 +22,14 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
......@@ -39,6 +39,7 @@ import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.JmsListenerEndpointRegistry;
import org.springframework.jms.config.MethodJmsListenerEndpoint;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
......@@ -60,6 +61,7 @@ import org.springframework.util.StringUtils;
* {@link EnableJms} Javadoc for complete usage details.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see JmsListener
* @see EnableJms
......@@ -69,11 +71,11 @@ import org.springframework.util.StringUtils;
* @see org.springframework.jms.config.AbstractJmsListenerEndpoint
* @see MethodJmsListenerEndpoint
*/
public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered,
ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
public class JmsListenerAnnotationBeanPostProcessor
implements BeanPostProcessor, Ordered, BeanFactoryAware, SmartInitializingSingleton {
/**
* The bean name of the default {@link JmsListenerContainerFactory}
* The bean name of the default {@link JmsListenerContainerFactory}.
*/
static final String DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "jmsListenerContainerFactory";
......@@ -82,9 +84,9 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
private String containerFactoryBeanName = DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME;
private final JmsHandlerMethodFactoryAdapter jmsHandlerMethodFactory = new JmsHandlerMethodFactoryAdapter();
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
private final JmsHandlerMethodFactoryAdapter jmsHandlerMethodFactory = new JmsHandlerMethodFactoryAdapter();
private final JmsListenerEndpointRegistrar registrar = new JmsListenerEndpointRegistrar();
......@@ -124,9 +126,50 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(jmsHandlerMethodFactory);
}
/**
* Making a {@link BeanFactory} available is optional; if not set,
* {@link JmsListenerConfigurer} beans won't get autodetected and an
* {@link #setEndpointRegistry endpoint registry} has to be explicitly configured.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
public void afterSingletonsInstantiated() {
this.registrar.setBeanFactory(this.beanFactory);
if (this.beanFactory instanceof ListableBeanFactory) {
Map<String, JmsListenerConfigurer> instances =
((ListableBeanFactory) this.beanFactory).getBeansOfType(JmsListenerConfigurer.class);
for (JmsListenerConfigurer configurer : instances.values()) {
configurer.configureJmsListeners(this.registrar);
}
}
if (this.registrar.getEndpointRegistry() == null) {
if (this.endpointRegistry == null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to find endpoint registry by bean name");
this.endpointRegistry = this.beanFactory.getBean(
AnnotationConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME, JmsListenerEndpointRegistry.class);
}
this.registrar.setEndpointRegistry(this.endpointRegistry);
}
if (this.containerFactoryBeanName != null) {
this.registrar.setContainerFactoryBeanName(this.containerFactoryBeanName);
}
// Set the custom handler method factory once resolved by the configurer
JmsHandlerMethodFactory handlerMethodFactory = this.registrar.getJmsHandlerMethodFactory();
if (handlerMethodFactory != null) {
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(handlerMethodFactory);
}
// Actually register all listeners
this.registrar.afterPropertiesSet();
}
......@@ -189,8 +232,9 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
JmsListenerContainerFactory<?> factory = null;
String containerFactoryBeanName = jmsListener.containerFactory();
if (StringUtils.hasText(containerFactoryBeanName)) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
try {
factory = this.applicationContext.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class);
factory = this.beanFactory.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanInitializationException("Could not register jms listener endpoint on [" +
......@@ -199,49 +243,7 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
}
}
registrar.registerEndpoint(endpoint, factory);
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() != this.applicationContext) {
return;
}
Map<String, JmsListenerConfigurer> instances =
this.applicationContext.getBeansOfType(JmsListenerConfigurer.class);
for (JmsListenerConfigurer configurer : instances.values()) {
configurer.configureJmsListeners(registrar);
}
this.registrar.setApplicationContext(this.applicationContext);
if (this.registrar.getEndpointRegistry() == null) {
if (this.endpointRegistry == null) {
this.endpointRegistry = this.applicationContext.getBean(
AnnotationConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME, JmsListenerEndpointRegistry.class);
}
this.registrar.setEndpointRegistry(this.endpointRegistry);
}
if (this.containerFactoryBeanName != null) {
this.registrar.setContainerFactoryBeanName(this.containerFactoryBeanName);
}
// Set the custom handler method factory once resolved by the configurer
JmsHandlerMethodFactory handlerMethodFactory = registrar.getJmsHandlerMethodFactory();
if (handlerMethodFactory != null) {
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(handlerMethodFactory);
}
// Create all the listeners and starts them
try {
this.registrar.afterPropertiesSet();
}
catch (Exception ex) {
throw new BeanInitializationException("Failed to initialize JmsListenerEndpointRegistrar", ex);
}
this.registrar.registerEndpoint(endpoint, factory);
}
private String getEndpointId(JmsListener jmsListener) {
......@@ -282,7 +284,7 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
private JmsHandlerMethodFactory createDefaultJmsHandlerMethodFactory() {
DefaultJmsHandlerMethodFactory defaultFactory = new DefaultJmsHandlerMethodFactory();
defaultFactory.setApplicationContext(applicationContext);
defaultFactory.setBeanFactory(beanFactory);
defaultFactory.afterPropertiesSet();
return defaultFactory;
}
......
......@@ -20,11 +20,10 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.messaging.converter.GenericMessageConverter;
......@@ -36,8 +35,6 @@ import org.springframework.messaging.handler.annotation.support.PayloadArgumentR
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
......@@ -57,15 +54,13 @@ import org.springframework.validation.Validator;
* can be converted
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see #setCustomArgumentResolvers(java.util.List)
* @see #setValidator(Validator)
* @see #setConversionService(ConversionService)
* @see #setConversionService
* @see #setValidator
* @see #setCustomArgumentResolvers
*/
public class DefaultJmsHandlerMethodFactory
implements JmsHandlerMethodFactory, InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
public class DefaultJmsHandlerMethodFactory implements JmsHandlerMethodFactory, BeanFactoryAware, InitializingBean {
private ConversionService conversionService = new DefaultFormattingConversionService();
......@@ -73,22 +68,17 @@ public class DefaultJmsHandlerMethodFactory
private Validator validator = new NoOpValidator();
private List<HandlerMethodArgumentResolver> customArgumentResolvers
= new ArrayList<HandlerMethodArgumentResolver>();
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private HandlerMethodArgumentResolverComposite argumentResolvers
= new HandlerMethodArgumentResolverComposite();
private final HandlerMethodArgumentResolverComposite argumentResolvers =
new HandlerMethodArgumentResolverComposite();
private BeanFactory beanFactory;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* Set the {@link ConversionService} to use to convert the original
* message payload or headers.
*
* @see HeaderMethodArgumentResolver
* @see GenericMessageConverter
*/
......@@ -96,24 +86,15 @@ public class DefaultJmsHandlerMethodFactory
this.conversionService = conversionService;
}
protected ConversionService getConversionService() {
return conversionService;
}
/**
* Set the {@link MessageConverter} to use. By default a {@link GenericMessageConverter}
* is used.
*
* @see GenericMessageConverter
*/
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
protected MessageConverter getMessageConverter() {
return messageConverter;
}
/**
* Set the Validator instance used for validating @Payload arguments
* @see org.springframework.validation.annotation.Validated
......@@ -123,27 +104,15 @@ public class DefaultJmsHandlerMethodFactory
this.validator = validator;
}
/**
* The configured Validator instance
*/
public Validator getValidator() {
return validator;
}
/**
* Set the list of custom {@code HandlerMethodArgumentResolver}s that will be used
* after resolvers for supported argument type.
* @param customArgumentResolvers the list of resolvers; never {@code null}.
* @param customArgumentResolvers the list of resolvers (never {@code null})
*/
public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> customArgumentResolvers) {
Assert.notNull(customArgumentResolvers, "The 'customArgumentResolvers' cannot be null.");
this.customArgumentResolvers = customArgumentResolvers;
}
public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
return customArgumentResolvers;
}
/**
* Configure the complete list of supported argument types effectively overriding
* the ones configured by default. This is an advanced option. For most use cases
......@@ -157,20 +126,26 @@ public class DefaultJmsHandlerMethodFactory
this.argumentResolvers.addResolvers(argumentResolvers);
}
public List<HandlerMethodArgumentResolver> getArgumentResolvers() {
return this.argumentResolvers.getResolvers();
/**
* A {@link BeanFactory} only needs to be available for placeholder resolution
* in handler method arguments; it's optional otherwise.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() {
if (messageConverter == null) {
messageConverter = new GenericMessageConverter(getConversionService());
if (this.messageConverter == null) {
this.messageConverter = new GenericMessageConverter(this.conversionService);
}
if (this.argumentResolvers.getResolvers().isEmpty()) {
this.argumentResolvers.addResolvers(initArgumentResolvers());
}
}
@Override
public InvocableHandlerMethod createInvocableHandlerMethod(Object bean, Method method) {
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(bean, method);
......@@ -179,27 +154,28 @@ public class DefaultJmsHandlerMethodFactory
}
protected List<HandlerMethodArgumentResolver> initArgumentResolvers() {
ConfigurableBeanFactory beanFactory =
(ClassUtils.isAssignableValue(ConfigurableApplicationContext.class, applicationContext)) ?
((ConfigurableApplicationContext) applicationContext).getBeanFactory() : null;
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
ConfigurableBeanFactory cbf = (this.beanFactory instanceof ConfigurableBeanFactory ?
(ConfigurableBeanFactory) this.beanFactory : null);
// Annotation-based argument resolution
resolvers.add(new HeaderMethodArgumentResolver(getConversionService(), beanFactory));
resolvers.add(new HeaderMethodArgumentResolver(this.conversionService, cbf));
resolvers.add(new HeadersMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new MessageMethodArgumentResolver());
resolvers.addAll(getCustomArgumentResolvers());
resolvers.add(new PayloadArgumentResolver(getMessageConverter(), getValidator()));
if (this.customArgumentResolvers != null) {
resolvers.addAll(this.customArgumentResolvers);
}
resolvers.add(new PayloadArgumentResolver(this.messageConverter, this.validator));
return resolvers;
}
private static final class NoOpValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
......
......@@ -19,9 +19,9 @@ package org.springframework.jms.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
/**
......@@ -29,24 +29,26 @@ import org.springframework.util.Assert;
* a {@link JmsListenerEndpointRegistry}.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see org.springframework.jms.annotation.JmsListenerConfigurer
*/
public class JmsListenerEndpointRegistrar implements ApplicationContextAware, InitializingBean {
public class JmsListenerEndpointRegistrar implements BeanFactoryAware, InitializingBean {
private JmsListenerEndpointRegistry endpointRegistry;
private String containerFactoryBeanName;
private JmsHandlerMethodFactory jmsHandlerMethodFactory;
private JmsListenerContainerFactory<?> containerFactory;
private JmsHandlerMethodFactory jmsHandlerMethodFactory;
private String containerFactoryBeanName;
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
private final List<JmsListenerEndpointDescriptor> endpointDescriptors =
new ArrayList<JmsListenerEndpointDescriptor>();
/**
* Set the {@link JmsListenerEndpointRegistry} instance to use.
*/
......@@ -59,27 +61,7 @@ public class JmsListenerEndpointRegistrar implements ApplicationContextAware, In
* registrar, may be {@code null}.
*/
public JmsListenerEndpointRegistry getEndpointRegistry() {
return endpointRegistry;
}
/**
* Set the bean name of the {@link JmsListenerContainerFactory} to use in
* case a {@link JmsListenerEndpoint} is registered with a {@code null}
* container factory. Alternatively, the container factory instance can
* be registered directly, see {@link #setContainerFactory(JmsListenerContainerFactory)}
*/
public void setContainerFactoryBeanName(String containerFactoryBeanName) {
this.containerFactoryBeanName = containerFactoryBeanName;
}
/**
* Set the {@link JmsListenerContainerFactory} to use in case a {@link JmsListenerEndpoint}
* is registered with a {@code null} container factory.
* <p>Alternatively, the bean name of the {@link JmsListenerContainerFactory} to use
* can be specified for a lazy lookup, see {@link #setContainerFactoryBeanName}.
*/
public void setContainerFactory(JmsListenerContainerFactory<?> containerFactory) {
this.containerFactory = containerFactory;
return this.endpointRegistry;
}
/**
......@@ -98,47 +80,48 @@ public class JmsListenerEndpointRegistrar implements ApplicationContextAware, In
* Return the custom {@link JmsHandlerMethodFactory} to use, if any.
*/
public JmsHandlerMethodFactory getJmsHandlerMethodFactory() {
return jmsHandlerMethodFactory;
return this.jmsHandlerMethodFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
/**
* Set the {@link JmsListenerContainerFactory} to use in case a {@link JmsListenerEndpoint}
* is registered with a {@code null} container factory.
* <p>Alternatively, the bean name of the {@link JmsListenerContainerFactory} to use
* can be specified for a lazy lookup, see {@link #setContainerFactoryBeanName}.
*/
public void setContainerFactory(JmsListenerContainerFactory<?> containerFactory) {
this.containerFactory = containerFactory;
}
/**
* Register a new {@link JmsListenerEndpoint} alongside the
* {@link JmsListenerContainerFactory} to use to create the underlying container.
* <p>The {@code factory} may be {@code null} if the default factory has to be
* used for that endpoint.
* Set the bean name of the {@link JmsListenerContainerFactory} to use in case
* a {@link JmsListenerEndpoint} is registered with a {@code null} container factory.
* Alternatively, the container factory instance can be registered directly:
* see {@link #setContainerFactory(JmsListenerContainerFactory)}.
* @see #setBeanFactory
*/
public void registerEndpoint(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) {
Assert.notNull(endpoint, "Endpoint must be set");
Assert.notNull(endpoint.getId(), "Endpoint id must be set");
// Factory may be null, we defer the resolution right before actually creating the container
this.endpointDescriptors.add(new JmsListenerEndpointDescriptor(endpoint, factory));
public void setContainerFactoryBeanName(String containerFactoryBeanName) {
this.containerFactoryBeanName = containerFactoryBeanName;
}
/**
* Register a new {@link JmsListenerEndpoint} using the default
* {@link JmsListenerContainerFactory} to create the underlying container.
* @see #setContainerFactory(JmsListenerContainerFactory)
* @see #registerEndpoint(JmsListenerEndpoint, JmsListenerContainerFactory)
* A {@link BeanFactory} only needs to be available in conjunction with
* {@link #setContainerFactoryBeanName}.
*/
public void registerEndpoint(JmsListenerEndpoint endpoint) {
registerEndpoint(endpoint, null);
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(applicationContext, "ApplicationContext must not be null");
startAllEndpoints();
public void afterPropertiesSet() {
registerAllEndpoints();
}
protected void startAllEndpoints() throws Exception {
for (JmsListenerEndpointDescriptor descriptor : endpointDescriptors) {
endpointRegistry.registerListenerContainer(
descriptor.endpoint, resolveContainerFactory(descriptor));
protected void registerAllEndpoints() {
for (JmsListenerEndpointDescriptor descriptor : this.endpointDescriptors) {
this.endpointRegistry.registerListenerContainer(descriptor.endpoint, resolveContainerFactory(descriptor));
}
}
......@@ -150,7 +133,8 @@ public class JmsListenerEndpointRegistrar implements ApplicationContextAware, In
return this.containerFactory;
}
else if (this.containerFactoryBeanName != null) {
this.containerFactory = this.applicationContext.getBean(
Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
this.containerFactory = this.beanFactory.getBean(
this.containerFactoryBeanName, JmsListenerContainerFactory.class);
return this.containerFactory; // Consider changing this if live change of the factory is required
}
......@@ -161,6 +145,29 @@ public class JmsListenerEndpointRegistrar implements ApplicationContextAware, In
}
}
/**
* Register a new {@link JmsListenerEndpoint} alongside the
* {@link JmsListenerContainerFactory} to use to create the underlying container.
* <p>The {@code factory} may be {@code null} if the default factory has to be
* used for that endpoint.
*/
public void registerEndpoint(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) {
Assert.notNull(endpoint, "Endpoint must be set");
Assert.notNull(endpoint.getId(), "Endpoint id must be set");
// Factory may be null, we defer the resolution right before actually creating the container
this.endpointDescriptors.add(new JmsListenerEndpointDescriptor(endpoint, factory));
}
/**
* Register a new {@link JmsListenerEndpoint} using the default
* {@link JmsListenerContainerFactory} to create the underlying container.
* @see #setContainerFactory(JmsListenerContainerFactory)
* @see #registerEndpoint(JmsListenerEndpoint, JmsListenerContainerFactory)
*/
public void registerEndpoint(JmsListenerEndpoint endpoint) {
registerEndpoint(endpoint, null);
}
private static class JmsListenerEndpointDescriptor {
......
......@@ -40,6 +40,7 @@ import static org.junit.Assert.*;
/**
* @author Stephane Nicoll
* @author Juergen Hoeller
*/
public class JmsListenerAnnotationBeanPostProcessorTests {
......@@ -62,9 +63,7 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
methodEndpoint.setupListenerContainer(listenerContainer);
assertNotNull(listenerContainer.getMessageListener());
context.start();
assertTrue("Should have been started " + container, container.isStarted());
context.close(); // Close and stop the listeners
assertTrue("Should have been stopped " + container, container.isStopped());
}
......
......@@ -16,8 +16,6 @@
package org.springframework.jms.config;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -31,7 +29,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestName;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
......@@ -44,8 +42,9 @@ import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
/**
*
* @author Stephane Nicoll
*/
public class DefaultJmsHandlerMethodFactoryTests {
......@@ -160,15 +159,13 @@ public class DefaultJmsHandlerMethodFactoryTests {
private DefaultJmsHandlerMethodFactory createInstance() {
DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
factory.setApplicationContext(new StaticApplicationContext());
factory.setBeanFactory(new StaticListableBeanFactory());
return factory;
}
private Method getListenerMethod(String methodName, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(SampleBean.class,
methodName, parameterTypes);
assertNotNull("no method found with name " + methodName
+ " and parameters " + Arrays.toString(parameterTypes));
Method method = ReflectionUtils.findMethod(SampleBean.class, methodName, parameterTypes);
assertNotNull("no method found with name " + methodName + " and parameters " + Arrays.toString(parameterTypes));
return method;
}
......@@ -187,6 +184,7 @@ public class DefaultJmsHandlerMethodFactoryTests {
}
}
static class CustomHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
......
......@@ -16,14 +16,10 @@
package org.springframework.jms.config;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
......@@ -33,7 +29,7 @@ import javax.jms.TextMessage;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.jms.StubTextMessage;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.SessionAwareMessageListener;
......@@ -42,8 +38,10 @@ import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
*
* @author Stephane Nicoll
*/
public class JmsListenerContainerFactoryIntegrationTests {
......@@ -54,6 +52,7 @@ public class JmsListenerContainerFactoryIntegrationTests {
private final JmsEndpointSampleBean sample = new JmsEndpointSampleBean();
@Before
public void setup() {
initializeFactory(factory);
......@@ -70,16 +69,6 @@ public class JmsListenerContainerFactoryIntegrationTests {
assertListenerMethodInvocation("expectFooBarUpperCase");
}
static class JmsEndpointSampleBean {
private final Map<String, Boolean> invocations = new HashMap<String, Boolean>();
public void expectFooBarUpperCase(@Payload String msg) {
invocations.put("expectFooBarUpperCase", true);
assertEquals("Unexpected payload message", "FOO-BAR", msg);
}
}
@SuppressWarnings("unchecked")
private void invokeListener(JmsListenerEndpoint endpoint, Message message) throws JMSException {
DefaultMessageListenerContainer messageListenerContainer =
......@@ -112,21 +101,31 @@ public class JmsListenerContainerFactoryIntegrationTests {
}
private Method getListenerMethod(String methodName, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(JmsEndpointSampleBean.class,
methodName, parameterTypes);
assertNotNull("no method found with name " + methodName
+ " and parameters " + Arrays.toString(parameterTypes));
Method method = ReflectionUtils.findMethod(JmsEndpointSampleBean.class, methodName, parameterTypes);
assertNotNull("no method found with name " + methodName + " and parameters " + Arrays.toString(parameterTypes));
return method;
}
private void initializeFactory(DefaultJmsHandlerMethodFactory factory) {
factory.setApplicationContext(new StaticApplicationContext());
factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet();
}
static class JmsEndpointSampleBean {
private final Map<String, Boolean> invocations = new HashMap<String, Boolean>();
public void expectFooBarUpperCase(@Payload String msg) {
invocations.put("expectFooBarUpperCase", true);
assertEquals("Unexpected payload message", "FOO-BAR", msg);
}
}
private static class UpperCaseMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
return new StubTextMessage(object.toString().toUpperCase());
......@@ -138,6 +137,5 @@ public class JmsListenerContainerFactoryIntegrationTests {
return content.toUpperCase();
}
}
}
}
......@@ -16,17 +16,16 @@
package org.springframework.jms.config;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import static org.junit.Assert.*;
/**
*
* @author Stephane Nicoll
*/
public class JmsListenerEndpointRegistrarTests {
......@@ -40,10 +39,11 @@ public class JmsListenerEndpointRegistrarTests {
private final JmsListenerContainerTestFactory containerFactory = new JmsListenerContainerTestFactory();
@Before
public void setup() {
registrar.setEndpointRegistry(registry);
registrar.setApplicationContext(new StaticApplicationContext());
registrar.setBeanFactory(new StaticListableBeanFactory());
}
@Test
......
......@@ -16,16 +16,11 @@
package org.springframework.jms.config;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.*;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.jms.Destination;
import javax.jms.InvalidDestinationException;
import javax.jms.JMSException;
......@@ -41,16 +36,16 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestName;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.jms.StubTextMessage;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.MessageListenerContainer;
import org.springframework.jms.listener.SimpleMessageListenerContainer;
import org.springframework.jms.listener.adapter.ReplyFailureException;
import org.springframework.jms.listener.adapter.ListenerExecutionFailedException;
import org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter;
import org.springframework.jms.support.JmsMessageHeaderAccessor;
import org.springframework.jms.listener.adapter.ReplyFailureException;
import org.springframework.jms.support.JmsHeaders;
import org.springframework.jms.support.JmsMessageHeaderAccessor;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
......@@ -65,8 +60,12 @@ import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
*
* @author Stephane Nicoll
*/
public class MethodJmsListenerEndpointTests {
......@@ -83,6 +82,7 @@ public class MethodJmsListenerEndpointTests {
private final JmsEndpointSampleBean sample = new JmsEndpointSampleBean();
@Before
public void setup() {
initializeFactory(factory);
......@@ -375,10 +375,8 @@ public class MethodJmsListenerEndpointTests {
}
private Method getListenerMethod(String methodName, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(JmsEndpointSampleBean.class,
methodName, parameterTypes);
assertNotNull("no method found with name " + methodName
+ " and parameters " + Arrays.toString(parameterTypes));
Method method = ReflectionUtils.findMethod(JmsEndpointSampleBean.class, methodName, parameterTypes);
assertNotNull("no method found with name " + methodName + " and parameters " + Arrays.toString(parameterTypes));
return method;
}
......@@ -395,12 +393,11 @@ public class MethodJmsListenerEndpointTests {
}
private void initializeFactory(DefaultJmsHandlerMethodFactory factory) {
factory.setApplicationContext(new StaticApplicationContext());
factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet();
}
private Validator testValidator(final String invalidValue) {
return new Validator() {
@Override
public boolean supports(Class<?> clazz) {
......@@ -520,11 +517,11 @@ public class MethodJmsListenerEndpointTests {
}
@SuppressWarnings("serial")
static class MyBean implements Serializable {
private String name;
}
}
......@@ -25,7 +25,7 @@ import javax.jms.TextMessage;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.jms.StubTextMessage;
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
import org.springframework.jms.support.JmsHeaders;
......@@ -38,7 +38,6 @@ import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
/**
*
* @author Stephane Nicoll
*/
public class MessagingMessageListenerAdapterTests {
......@@ -124,7 +123,7 @@ public class MessagingMessageListenerAdapterTests {
}
private void initializeFactory(DefaultJmsHandlerMethodFactory factory) {
factory.setApplicationContext(new StaticApplicationContext());
factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册