INT-3601: Use ChannelResolver instead of BF

JIRA: https://jira.spring.io/browse/INT-3601

* Move `setChannelResolver(DestinationResolver<MessageChannel> channelResolver)` to the `IntegrationObjectSupport`
* Introduce `IntegrationObjectSupport#getChannelResolver()`
* Change all `IntegrationObjectSupport` inheritors to use `getChannelResolver()` instead of direct `beanFactory` usage
* Fix `ServiceActivatorEndpointTests` do not fall

INT-3601: Addressing PR (JIRA) comments

Fixes failing tests

INT-3601: Address PR comments
This commit is contained in:
Artem Bilan
2015-01-16 16:43:18 +02:00
committed by Gary Russell
parent a4a6b7094b
commit 45eaadd6ac
15 changed files with 134 additions and 154 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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. You may obtain a copy of the License at
@@ -461,14 +461,8 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageP
if (this.discardChannelName != null) {
synchronized (this) {
if (this.discardChannelName != null) {
try {
this.discardChannel = getBeanFactory().getBean(this.discardChannelName, MessageChannel.class);
this.discardChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.discardChannelName + "' in the BeanFactory.");
}
this.discardChannel = getChannelResolver().resolveDestination(this.discardChannelName);
this.discardChannelName = null;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -45,6 +45,8 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.core.BeanFactoryMessageChannelDestinationResolver;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -92,6 +94,8 @@ public class ConsumerEndpointFactoryBean
private volatile List<Advice> adviceChain;
private volatile DestinationResolver<MessageChannel> channelResolver;
public void setHandler(MessageHandler handler) {
Assert.notNull(handler, "handler must not be null");
synchronized (this.handlerMonitor) {
@@ -112,6 +116,17 @@ public class ConsumerEndpointFactoryBean
this.pollerMetadata = pollerMetadata;
}
/**
* Specify the {@link DestinationResolver} strategy to use.
* The default is a BeanFactoryChannelResolver.
* @param channelResolver The channel resolver.
* @since 4.1.3
*/
public void setChannelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.channelResolver = channelResolver;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
@@ -190,7 +205,10 @@ public class ConsumerEndpointFactoryBean
}
}
}
this.initializeEndpoint();
if (this.channelResolver == null) {
this.channelResolver = new BeanFactoryMessageChannelDestinationResolver(this.beanFactory);
}
initializeEndpoint();
}
@Override
@@ -221,9 +239,7 @@ public class ConsumerEndpointFactoryBean
}
MessageChannel channel = null;
if (StringUtils.hasText(this.inputChannelName)) {
Assert.isTrue(this.beanFactory.containsBean(this.inputChannelName), "no such input channel '"
+ this.inputChannelName + "' for endpoint '" + this.beanName + "'");
channel = this.beanFactory.getBean(this.inputChannelName, MessageChannel.class);
channel = this.channelResolver.resolveDestination(this.inputChannelName);
}
if (this.inputChannel != null) {
channel = this.inputChannel;

View File

@@ -1,5 +1,5 @@
/*
* 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.
@@ -29,7 +29,9 @@ import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.BeanFactoryMessageChannelDestinationResolver;
import org.springframework.messaging.core.DestinationResolutionException;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -39,6 +41,7 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*/
public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<SourcePollingChannelAdapter>,
BeanFactoryAware, BeanNameAware, BeanClassLoaderAware, InitializingBean, SmartLifecycle {
@@ -67,6 +70,8 @@ public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<Sourc
private volatile boolean initialized;
private volatile DestinationResolver<MessageChannel> channelResolver;
private final Object initializationMonitor = new Object();
public void setSource(MessageSource<?> source) {
@@ -97,27 +102,45 @@ public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<Sourc
this.phase = phase;
}
/**
* Specify the {@link DestinationResolver} strategy to use.
* The default is a BeanFactoryChannelResolver.
* @param channelResolver The channel resolver.
* @since 4.1.3
*/
public void setChannelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.channelResolver = channelResolver;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
Assert.isInstanceOf(ConfigurableBeanFactory.class, beanFactory,
"a ConfigurableBeanFactory is required");
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void afterPropertiesSet() throws Exception {
this.initializeAdapter();
if (this.channelResolver == null) {
this.channelResolver = new BeanFactoryMessageChannelDestinationResolver(this.beanFactory);
}
initializeAdapter();
}
public SourcePollingChannelAdapter getObject() throws Exception {
if (this.adapter == null) {
this.initializeAdapter();
initializeAdapter();
}
return this.adapter;
}
@@ -139,13 +162,7 @@ public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<Sourc
if (StringUtils.hasText(this.outputChannelName)) {
Assert.isNull(this.outputChannel, "'outputChannelName' and 'outputChannel' are mutually exclusive.");
try {
this.outputChannel = this.beanFactory.getBean(this.outputChannelName, MessageChannel.class);
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.outputChannelName + "' in the BeanFactory.");
}
this.outputChannel = this.channelResolver.resolveDestination(this.outputChannelName);
}
Assert.notNull(this.outputChannel, "outputChannel is required");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -35,8 +35,11 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.MessageBuilderFactory;
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
import org.springframework.integration.support.context.NamedComponent;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -67,6 +70,8 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
private final ConversionService defaultConversionService = new DefaultConversionService();
private volatile DestinationResolver<MessageChannel> channelResolver;
private volatile String beanName;
private volatile String componentName;
@@ -126,6 +131,16 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
this.applicationContext = applicationContext;
}
/**
* Specify the {@link DestinationResolver} strategy to use.
* The default is a BeanFactoryChannelResolver.
* @param channelResolver The channel resolver.
*/
public void setChannelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.channelResolver = channelResolver;
}
@Override
public final void afterPropertiesSet() {
try {
@@ -160,6 +175,13 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
return this.taskScheduler;
}
protected DestinationResolver<MessageChannel> getChannelResolver() {
if (this.channelResolver == null) {
this.channelResolver = new BeanFactoryChannelResolver(this.beanFactory);
}
return this.channelResolver;
}
protected void setTaskScheduler(TaskScheduler taskScheduler) {
Assert.notNull(taskScheduler, "taskScheduler must not be null");
this.taskScheduler = taskScheduler;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -158,15 +158,8 @@ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHa
if (this.discardChannelName != null) {
synchronized (this) {
if (this.discardChannelName != null) {
try {
this.discardChannel = this.getBeanFactory()
.getBean(this.discardChannelName, MessageChannel.class);
this.discardChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.discardChannelName + "' in the BeanFactory.");
}
this.discardChannel = getChannelResolver().resolveDestination(this.discardChannelName);
this.discardChannelName = null;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,7 +16,6 @@
package org.springframework.integration.gateway;
import org.springframework.beans.BeansException;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.EventDrivenConsumer;
@@ -34,7 +33,6 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.core.DestinationResolutionException;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.util.Assert;
@@ -236,16 +234,8 @@ public abstract class MessagingGatewaySupport extends AbstractEndpoint implement
if (this.requestChannelName != null) {
synchronized (this) {
if (this.requestChannelName != null) {
try {
Assert.state(getBeanFactory() != null,
"A bean factory is required to resolve the requestChannel at runtime.");
this.requestChannel = getBeanFactory().getBean(this.requestChannelName, MessageChannel.class);
this.requestChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.requestChannelName + "' in the BeanFactory.");
}
this.requestChannel = getChannelResolver().resolveDestination(this.requestChannelName);
this.requestChannelName = null;
}
}
}
@@ -256,16 +246,8 @@ public abstract class MessagingGatewaySupport extends AbstractEndpoint implement
if (this.replyChannelName != null) {
synchronized (this) {
if (this.replyChannelName != null) {
try {
Assert.state(getBeanFactory() != null,
"A bean factory is required to resolve the replyChannel at runtime.");
this.replyChannel = getBeanFactory().getBean(this.replyChannelName, MessageChannel.class);
this.replyChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.replyChannelName + "' in the BeanFactory.");
}
this.replyChannel = getChannelResolver().resolveDestination(this.replyChannelName);
this.replyChannelName = null;
}
}
}
@@ -276,16 +258,8 @@ public abstract class MessagingGatewaySupport extends AbstractEndpoint implement
if (this.errorChannelName != null) {
synchronized (this) {
if (this.errorChannelName != null) {
try {
Assert.state(getBeanFactory() != null,
"A bean factory is required to resolve the errorChannel at runtime.");
this.errorChannel = getBeanFactory().getBean(this.errorChannelName, MessageChannel.class);
this.errorChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.errorChannelName + "' in the BeanFactory.");
}
this.errorChannel = getChannelResolver().resolveDestination(this.errorChannelName);
this.errorChannelName = null;
}
}
}

View File

@@ -21,7 +21,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.beans.BeansException;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.core.MessagingTemplate;
@@ -32,7 +31,6 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.core.DestinationResolutionException;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -71,15 +69,6 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
this.outputChannelName = outputChannelName;//NOSONAR (inconsistent sync)
}
/**
* Set the DestinationResolver&lt;MessageChannel&gt; to be used when there is no default output channel.
* @param channelResolver The channel resolver.
*/
public void setChannelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.messagingTemplate.setDestinationResolver(channelResolver);
}
@Override
protected void onInit() throws Exception {
super.onInit();
@@ -88,22 +77,15 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
if (getBeanFactory() != null) {
this.messagingTemplate.setBeanFactory(getBeanFactory());
}
this.messagingTemplate.setDestinationResolver(getChannelResolver());
}
public MessageChannel getOutputChannel() {
if (this.outputChannelName != null) {
synchronized (this) {
if (this.outputChannelName != null) {
try {
Assert.state(getBeanFactory() != null,
"A bean factory is required to resolve the outputChannel at runtime.");
this.outputChannel = getBeanFactory().getBean(this.outputChannelName, MessageChannel.class);
this.outputChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.outputChannelName + "' in the BeanFactory.");
}
this.outputChannel = getChannelResolver().resolveDestination(this.outputChannelName);
this.outputChannelName = null;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -46,14 +46,13 @@ import org.springframework.util.StringUtils;
* @author Oleg Zhurakousky
* @author Gunnar Hillert
* @author Gary Russell
* @author Artem Bilan
* @since 2.1
*/
public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter implements MappingMessageRouterManagement {
private volatile Map<String, String> channelMappings = new ConcurrentHashMap<String, String>();
private volatile DestinationResolver<MessageChannel> channelResolver;
private volatile String prefix;
private volatile String suffix;
@@ -64,7 +63,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
/**
* Provide mappings from channel keys to channel names.
* Channel names will be resolved by the {@link DestinationResolver}.
*
* @param channelMappings The channel mappings.
*/
@Override
@@ -76,22 +74,8 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
this.doSetChannelMappings(newChannelMappings);
}
/**
* Specify the {@link DestinationResolver} strategy to use.
* The default is a BeanFactoryChannelResolver.
* This is considered an infrastructural configuration option and
* as of 2.1 has been deprecated as a configuration-driven attribute.
*
* @param channelResolver The channel resolver.
*/
public void setChannelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.channelResolver = channelResolver;
}
/**
* Specify a prefix to be added to each channel name prior to resolution.
*
* @param prefix The prefix.
*/
public void setPrefix(String prefix) {
@@ -100,7 +84,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
/**
* Specify a suffix to be added to each channel name prior to resolution.
*
* @param suffix The suffix.
*/
public void setSuffix(String suffix) {
@@ -110,7 +93,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
/**
* Specify whether this router should ignore any failure to resolve a channel name to
* an actual MessageChannel instance when delegating to the ChannelResolver strategy.
*
* @param resolutionRequired true if resolution is required.
*/
public void setResolutionRequired(boolean resolutionRequired) {
@@ -120,7 +102,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
/**
* Returns an unmodifiable version of the channel mappings.
* This is intended for use by subclasses only.
*
* @return The channel mappings.
*/
@Override
@@ -131,7 +112,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
/**
* Add a channel mapping from the provided key to channel name.
*
* @param key The key.
* @param channelName The channel name.
*/
@@ -143,7 +123,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
/**
* Remove a channel mapping for the given key if present.
*
* @param key The key.
*/
@Override
@@ -152,25 +131,10 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
this.channelMappings.remove(key);
}
@Override
public void onInit() {
try {
super.onInit();
}
catch (Exception e) {
throw new IllegalStateException(e);
}
BeanFactory beanFactory = this.getBeanFactory();
if (this.channelResolver == null && beanFactory != null) {
this.channelResolver = new BeanFactoryChannelResolver(beanFactory);
}
}
/**
* Subclasses must implement this method to return the channel keys.
* A "key" might be present in this router's "channelMappings", or it
* could be the channel's name or even the Message Channel instance itself.
*
* @param message The message.
* @return The channel keys.
*/
@@ -193,7 +157,6 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
* <p>Mappings must be delimited with newlines, for example:
* <p>{@code "@'myRouter.handler'.replaceChannelMappings('foo=qux \n baz=bar')"}.
* @param channelMappings The channel mappings.
*
* @since 4.0
*/
@Override
@@ -218,13 +181,9 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
}
private MessageChannel resolveChannelForName(String channelName, Message<?> message) {
if (this.channelResolver == null) {
this.onInit();
}
Assert.state(this.channelResolver != null, "unable to resolve channel names, no ChannelResolver available");
MessageChannel channel = null;
try {
channel = this.channelResolver.resolveDestination(channelName);
channel = getChannelResolver().resolveDestination(channelName);
}
catch (DestinationResolutionException e) {
if (this.resolutionRequired) {

View File

@@ -46,7 +46,7 @@ class AbstractMessageProcessingRouter extends AbstractMappingMessageRouter
@Override
public final void onInit() {
public final void onInit() throws Exception {
super.onInit();
if (this.messageProcessor instanceof AbstractMessageProcessor) {
((AbstractMessageProcessor<?>) this.messageProcessor).setConversionService(this.getConversionService());

View File

@@ -181,15 +181,8 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
if (this.defaultOutputChannelName != null) {
synchronized (this) {
if (this.defaultOutputChannelName != null) {
try {
this.defaultOutputChannel = getBeanFactory()
.getBean(this.defaultOutputChannelName, MessageChannel.class);
this.defaultOutputChannelName = null;
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.defaultOutputChannelName + "' in the BeanFactory.");
}
this.defaultOutputChannel = getChannelResolver().resolveDestination(this.defaultOutputChannelName);
this.defaultOutputChannelName = null;
}
}
}

View File

@@ -148,7 +148,7 @@ public class RecipientListRouter extends AbstractMessageRouter
public void addRecipient(String channelName, String selectorExpression) {
Assert.hasText(channelName, "'channelName' must not be empty.");
Assert.hasText(selectorExpression, "'selectorExpression' must not be empty.");
MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
MessageChannel channel = getChannelResolver().resolveDestination(channelName);
ExpressionEvaluatingSelector expressionEvaluatingSelector = new ExpressionEvaluatingSelector(selectorExpression);
expressionEvaluatingSelector.setBeanFactory(this.getBeanFactory());
this.recipients.add(new Recipient(channel, expressionEvaluatingSelector));
@@ -158,7 +158,7 @@ public class RecipientListRouter extends AbstractMessageRouter
@ManagedOperation
public void addRecipient(String channelName) {
Assert.hasText(channelName, "'channelName' must not be empty.");
MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
MessageChannel channel = getChannelResolver().resolveDestination(channelName);
this.recipients.add(new Recipient(channel));
}
@@ -166,7 +166,7 @@ public class RecipientListRouter extends AbstractMessageRouter
@ManagedOperation
public int removeRecipient(String channelName) {
int counter = 0;
MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
MessageChannel channel = getChannelResolver().resolveDestination(channelName);
for (Iterator<Recipient> it = this.recipients.iterator(); it.hasNext(); ) {
if (it.next().getChannel() == channel) {
it.remove();
@@ -180,7 +180,7 @@ public class RecipientListRouter extends AbstractMessageRouter
@ManagedOperation
public int removeRecipient(String channelName, String selectorExpression) {
int counter = 0;
MessageChannel targetChannel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
MessageChannel targetChannel = getChannelResolver().resolveDestination(channelName);
for (Iterator<Recipient> it = this.recipients.iterator(); it.hasNext(); ) {
Recipient next = it.next();
MessageSelector selector = next.getSelector();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-2015 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,6 +23,8 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.BeanFactoryMessageChannelDestinationResolver;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -58,11 +60,27 @@ public class TransactionSynchronizationFactoryBean implements FactoryBean<Defaul
private volatile String afterRollbackChannelName;
private volatile DestinationResolver<MessageChannel> channelResolver;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Specify the {@link DestinationResolver} strategy to use.
* The default is a BeanFactoryChannelResolver.
* @param channelResolver The channel resolver.
* @return current TransactionSynchronizationFactoryBean
* @since 4.1.3
*/
public TransactionSynchronizationFactoryBean channelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.channelResolver = channelResolver;
return this;
}
public TransactionSynchronizationFactoryBean beforeCommit(String expression) {
return beforeCommit(expression, this.beforeCommitChannel);
}
@@ -143,6 +161,9 @@ public class TransactionSynchronizationFactoryBean implements FactoryBean<Defaul
@Override
public DefaultTransactionSynchronizationFactory getObject() throws Exception {
if (this.channelResolver == null) {
this.channelResolver = new BeanFactoryMessageChannelDestinationResolver(this.beanFactory);
}
ExpressionEvaluatingTransactionSynchronizationProcessor processor =
new ExpressionEvaluatingTransactionSynchronizationProcessor();
@@ -157,21 +178,21 @@ public class TransactionSynchronizationFactoryBean implements FactoryBean<Defaul
}
if (StringUtils.hasText(this.beforeCommitChannelName)) {
this.beforeCommitChannel = this.beanFactory.getBean(this.beforeCommitChannelName, MessageChannel.class);
this.beforeCommitChannel = this.channelResolver.resolveDestination(this.beforeCommitChannelName);
}
if (this.beforeCommitChannel != null) {
processor.setBeforeCommitChannel(this.beforeCommitChannel);
}
if (StringUtils.hasText(this.afterCommitChannelName)) {
this.afterCommitChannel = this.beanFactory.getBean(this.afterCommitChannelName, MessageChannel.class);
this.afterCommitChannel = this.channelResolver.resolveDestination(this.afterCommitChannelName);
}
if (this.afterCommitChannel != null) {
processor.setAfterCommitChannel(this.afterCommitChannel);
}
if (StringUtils.hasText(this.afterRollbackChannelName)) {
this.afterRollbackChannel = this.beanFactory.getBean(this.afterRollbackChannelName, MessageChannel.class);
this.afterRollbackChannel = this.channelResolver.resolveDestination(this.afterRollbackChannelName);
}
if (this.afterRollbackChannel != null) {
processor.setAfterRollbackChannel(this.afterRollbackChannel);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import org.mockito.Mockito;
@@ -90,6 +91,8 @@ public class ServiceActivatorEndpointTests {
channelResolver.addChannel("testChannel", channel);
ServiceActivatingHandler endpoint = this.createEndpoint();
endpoint.setChannelResolver(channelResolver);
endpoint.setBeanFactory(mock(BeanFactory.class));
endpoint.afterPropertiesSet();
Message<?> message = MessageBuilder.withPayload("foo")
.setReplyChannelName("testChannel").build();
endpoint.handleMessage(message);
@@ -113,6 +116,8 @@ public class ServiceActivatorEndpointTests {
TestChannelResolver channelResolver = new TestChannelResolver();
channelResolver.addChannel("replyChannel2", replyChannel2);
endpoint.setChannelResolver(channelResolver);
endpoint.setBeanFactory(mock(BeanFactory.class));
endpoint.afterPropertiesSet();
Message<String> testMessage1 = MessageBuilder.withPayload("bar")
.setReplyChannel(replyChannel1).build();
endpoint.handleMessage(testMessage1);
@@ -209,7 +214,7 @@ public class ServiceActivatorEndpointTests {
@Test
public void testBeanFactoryPopulation() {
ServiceActivatingHandler endpoint = this.createEndpoint();
BeanFactory mock = Mockito.mock(BeanFactory.class);
BeanFactory mock = mock(BeanFactory.class);
endpoint.setBeanFactory(mock);
endpoint.afterPropertiesSet();
Object beanFactory = TestUtils.getPropertyValue(endpoint, "processor.beanFactory");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -85,6 +85,7 @@ public class MessageHandlerChainTests {
chain.setBeanName("testChain");
chain.setHandlers(handlers);
chain.setOutputChannel(outputChannel);
chain.setBeanFactory(mock(BeanFactory.class));
chain.handleMessage(message);
Mockito.verify(outputChannel).send(Mockito.eq(message));
}
@@ -112,6 +113,7 @@ public class MessageHandlerChainTests {
MessageHandlerChain chain = new MessageHandlerChain();
chain.setBeanName("testChain");
chain.setHandlers(handlers);
chain.setBeanFactory(mock(BeanFactory.class));
chain.handleMessage(message);
}
@@ -125,6 +127,7 @@ public class MessageHandlerChainTests {
MessageHandlerChain chain = new MessageHandlerChain();
chain.setBeanName("testChain");
chain.setHandlers(handlers);
chain.setBeanFactory(mock(BeanFactory.class));
chain.handleMessage(message);
Mockito.verify(outputChannel).send(Mockito.any(Message.class));
}

View File

@@ -153,6 +153,7 @@ public class AdvisedMessageHandlerTests {
List<Advice> adviceChain = new ArrayList<Advice>();
adviceChain.add(advice);
handler.setAdviceChain(adviceChain);
handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet();
// advice with success