INT-3115 One EvaluationContext FB Per Context
Move definition of the IntegrationEvaluationContextFactoryBean from DefaultConfiguringBeanFactoryPostProcessor to AbstractIntegrationNamespaceHandler. We need a separate eval contexts for each app context so that child contexts get the correct BeanResolver. Add Test For IECFB and Parent Context
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<bean id="bar" class="java.lang.String">
|
||||
<constructor-arg value="bar"/>
|
||||
</bean>
|
||||
|
||||
<int:transformer input-channel="input" output-channel="output" expression="@foo + @bar"/>
|
||||
|
||||
<int:channel id="output">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<bean class="org.springframework.integration.expression.ParentContextTests$Foo" />
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<bean id="foo" class="java.lang.String">
|
||||
<constructor-arg value="foo"/>
|
||||
</bean>
|
||||
|
||||
<int:transformer input-channel="parentIn" output-channel="parentOut" expression="@foo"/>
|
||||
|
||||
<int:channel id="parentOut">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<bean class="org.springframework.integration.expression.ParentContextTests$Foo" />
|
||||
|
||||
<bean class="org.springframework.integration.expression.ParentContextTests$Foo" />
|
||||
|
||||
</beans>
|
||||
@@ -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<EvaluationContext> evalContexts = new ArrayList<EvaluationContext>();
|
||||
|
||||
/**
|
||||
* 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<String>("baz"));
|
||||
Message<?> out = child.getBean("output", QueueChannel.class).receive(0);
|
||||
assertNotNull(out);
|
||||
assertEquals("foobar", out.getPayload());
|
||||
child.getBean("parentIn", MessageChannel.class).send(new GenericMessage<String>("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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user