diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java
index 1b269621ea..57985316a0 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java
@@ -16,21 +16,28 @@
package org.springframework.integration.config.xml;
+import static org.springframework.integration.context.IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.ManagedSet;
+import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
import org.springframework.integration.config.xml.ChannelInitializer.AutoCreateCandidatesCollector;
+import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.integration.expression.IntegrationEvaluationContextAwareBeanPostProcessor;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
/**
* Base class for NamespaceHandlers that registers a BeanFactoryPostProcessor
@@ -59,6 +66,7 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
public final BeanDefinition parse(Element element, ParserContext parserContext) {
this.verifySchemaVersion(element, parserContext);
this.registerImplicitChannelCreator(parserContext);
+ this.registerIntegrationEvaluationContext(parserContext);
this.registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(parserContext);
return this.delegate.parse(element, parserContext);
}
@@ -90,8 +98,8 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
}
// ChannelInitializer$AutoCreateCandidatesCollector
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
- // unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry
- // therefore we need to call containsBeanDefinition(..) which does not consider parent registry
+ // unlike DefaultConfiguringBeanFactoryPostProcessor, we need one of these per registry
+ // therefore we need to call containsBeanDefinition(..) which does not consider the parent registry
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).
containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
}
@@ -107,6 +115,32 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
}
}
+ private void registerIntegrationEvaluationContext(ParserContext parserContext) {
+ boolean alreadyRegistered = false;
+ if (parserContext.getRegistry() instanceof ListableBeanFactory) {
+ // unlike DefaultConfiguringBeanFactoryPostProcessor, we need one of these per registry
+ // therefore we need to call containsBeanDefinition(..) which does not consider the parent registry
+ alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBeanDefinition(
+ INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
+ }
+ else {
+ alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
+ }
+ if (!alreadyRegistered) {
+ BeanDefinitionBuilder integrationEvaluationContextBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(IntegrationEvaluationContextFactoryBean.class);
+ integrationEvaluationContextBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ BeanDefinitionHolder integrationEvaluationContextHolder = new BeanDefinitionHolder(
+ integrationEvaluationContextBuilder.getBeanDefinition(),
+ IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
+ BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder,
+ parserContext.getRegistry());
+ RootBeanDefinition integrationEvalContextBPP = new RootBeanDefinition(
+ IntegrationEvaluationContextAwareBeanPostProcessor.class);
+ BeanDefinitionReaderUtils.registerWithGeneratedName(integrationEvalContextBPP, parserContext.getRegistry());
+ }
+ }
+
private void registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(ParserContext parserContext) {
boolean alreadyRegistered = false;
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java
index 96506e9b7b..92a3f211d2 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java
@@ -32,9 +32,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.integration.channel.NullChannel;
-import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
import org.springframework.integration.context.IntegrationContextUtils;
-import org.springframework.integration.expression.IntegrationEvaluationContextAwareBeanPostProcessor;
/**
* A {@link BeanFactoryPostProcessor} implementation that provides default beans for the error handling and task
@@ -44,13 +42,14 @@ import org.springframework.integration.expression.IntegrationEvaluationContextAw
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Artem Bilan
+ * @author Gary Russell
*/
class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static final String ERROR_LOGGER_BEAN_NAME = "_org.springframework.integration.errorLogger";
- private Log logger = LogFactory.getLog(this.getClass());
+ private final Log logger = LogFactory.getLog(this.getClass());
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
@@ -64,10 +63,6 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
this.registerTaskScheduler(registry);
}
this.registerIdGeneratorConfigurer(registry);
- if (!beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME)) {
- this.registerIntegrationEvaluationContext(registry);
- beanFactory.addBeanPostProcessor(new IntegrationEvaluationContextAwareBeanPostProcessor(beanFactory));
- }
}
else if (logger.isWarnEnabled()) {
logger.warn("BeanFactory is not a BeanDefinitionRegistry. The default '"
@@ -78,16 +73,6 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
}
}
- private void registerIntegrationEvaluationContext(BeanDefinitionRegistry registry) {
- BeanDefinitionBuilder integrationEvaluationContextBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- IntegrationEvaluationContextFactoryBean.class);
- integrationEvaluationContextBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- BeanDefinitionHolder integrationEvaluationContextHolder = new BeanDefinitionHolder(
- integrationEvaluationContextBuilder.getBeanDefinition(),
- IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
- BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder, registry);
- }
-
private void registerIdGeneratorConfigurer(BeanDefinitionRegistry registry) {
String listenerClassName = "org.springframework.integration.config.IdGeneratorConfigurer";
String[] definitionNames = registry.getBeanDefinitionNames();
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java
index c7b41c98f7..e93451f0e1 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java
@@ -18,19 +18,22 @@ package org.springframework.integration.expression;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.context.IntegrationContextUtils;
/**
* @author Artem Bilan
+ * @author Gary Russell
* @since 3.0
*/
-public class IntegrationEvaluationContextAwareBeanPostProcessor implements BeanPostProcessor {
+public class IntegrationEvaluationContextAwareBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
- private final BeanFactory beanFactory;
+ private volatile BeanFactory beanFactory;
- public IntegrationEvaluationContextAwareBeanPostProcessor(BeanFactory beanFactory) {
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ChildContext-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/expression/ChildContext-context.xml
new file mode 100644
index 0000000000..a4c0aee2bd
--- /dev/null
+++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ChildContext-context.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml
new file mode 100644
index 0000000000..8f0c3e9086
--- /dev/null
+++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java
new file mode 100644
index 0000000000..455496787c
--- /dev/null
+++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2013 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.integration.expression;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.message.GenericMessage;
+import org.springframework.integration.test.util.TestUtils;
+
+/**
+ * @author Gary Russell
+ * @since 3.0
+ *
+ */
+public class ParentContextTests {
+
+ private static final List evalContexts = new ArrayList();
+
+ /**
+ * Verifies that beans in hierarchical contexts get an evaluation context that has the proper
+ * BeanResolver. Verifies that the two Foos in the parent context get an evaluation context
+ * with the same bean resolver. Verifies that the one Foo in the child context gets a different
+ * bean resolver. Verifies that bean references in SpEL expressions to beans in the child
+ * and parent contexts work.
+ */
+ @Test
+ public void testSpelBeanReferencesInChildAndParent() {
+ ApplicationContext parent = new ClassPathXmlApplicationContext("ParentContext-context.xml", this.getClass());
+ assertEquals(2, evalContexts.size());
+ ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(parent);
+ child.setConfigLocation("org/springframework/integration/expression/ChildContext-context.xml");
+ child.refresh();
+ assertEquals(3, evalContexts.size());
+ assertSame(evalContexts.get(0).getBeanResolver(), evalContexts.get(1).getBeanResolver());
+ assertNotSame(evalContexts.get(1).getBeanResolver(), evalContexts.get(2).getBeanResolver());
+ assertSame(parent, TestUtils.getPropertyValue(evalContexts.get(0).getBeanResolver(), "beanFactory"));
+ assertSame(child, TestUtils.getPropertyValue(evalContexts.get(2).getBeanResolver(), "beanFactory"));
+
+ // Test transformer expressions
+ child.getBean("input", MessageChannel.class).send(new GenericMessage("baz"));
+ Message> out = child.getBean("output", QueueChannel.class).receive(0);
+ assertNotNull(out);
+ assertEquals("foobar", out.getPayload());
+ child.getBean("parentIn", MessageChannel.class).send(new GenericMessage("bar"));
+ out = child.getBean("parentOut", QueueChannel.class).receive(0);
+ assertNotNull(out);
+ assertEquals("foo", out.getPayload());
+ }
+
+ public static class Foo implements IntegrationEvaluationContextAware {
+
+ @Override
+ public void setIntegrationEvaluationContext(EvaluationContext evaluationContext) {
+ evalContexts.add(evaluationContext);
+ }
+
+ }
+}