Fix IntComponentSpec for ctx hooks
Since `IntegrationComponentSpec` is a `FactoryBean`, we need to care about `Aware` and `init` & `destroy` hooks our selves or delegate them through the `FactoryBean` wrapper * Implement `InitializingBean` and `DisposableBean` on the `IntegrationComponentSpec` * Call the `Aware` hooks from the `IntegrationFlowBeanPostProcessor` **Cherry-pick to 5.0.x**
This commit is contained in:
committed by
Gary Russell
parent
2126e9b9b5
commit
4b1d179956
@@ -21,18 +21,30 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanCreationNotAllowedException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.EmbeddedValueResolver;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.DescriptiveResource;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
@@ -57,6 +69,7 @@ import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* A {@link BeanPostProcessor} to parse {@link IntegrationFlow} beans and
|
||||
@@ -69,20 +82,26 @@ import org.springframework.util.StringUtils;
|
||||
* @since 5.0
|
||||
*/
|
||||
public class IntegrationFlowBeanPostProcessor
|
||||
implements BeanPostProcessor, BeanFactoryAware, SmartInitializingSingleton {
|
||||
implements BeanPostProcessor, ApplicationContextAware, SmartInitializingSingleton {
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private IntegrationFlowContext flowContext;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
|
||||
"To use Spring Integration Java DSL the 'beanFactory' has to be an instance of " +
|
||||
"'ConfigurableListableBeanFactory'. Consider using 'GenericApplicationContext' implementation."
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext,
|
||||
"To use Spring Integration Java DSL the 'applicationContext' has to be an instance of " +
|
||||
"'ConfigurableApplicationContext'. Consider using 'GenericApplicationContext' implementation."
|
||||
);
|
||||
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
|
||||
this.beanFactory = this.applicationContext.getBeanFactory();
|
||||
this.embeddedValueResolver = new EmbeddedValueResolver(this.beanFactory);
|
||||
this.flowContext = this.beanFactory.getBean(IntegrationFlowContext.class);
|
||||
Assert.notNull(this.flowContext, "There must be an IntegrationFlowContext in the application context");
|
||||
}
|
||||
@@ -96,7 +115,7 @@ public class IntegrationFlowBeanPostProcessor
|
||||
return processIntegrationFlowImpl((IntegrationFlow) bean, beanName);
|
||||
}
|
||||
if (bean instanceof IntegrationComponentSpec) {
|
||||
processIntegrationComponentSpec((IntegrationComponentSpec<?, ?>) bean);
|
||||
processIntegrationComponentSpec(beanName, (IntegrationComponentSpec<?, ?>) bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
@@ -280,7 +299,11 @@ public class IntegrationFlowBeanPostProcessor
|
||||
return isLambda(flow) ? standardIntegrationFlow : flow;
|
||||
}
|
||||
|
||||
private void processIntegrationComponentSpec(IntegrationComponentSpec<?, ?> bean) {
|
||||
private void processIntegrationComponentSpec(String beanName, IntegrationComponentSpec<?, ?> bean) {
|
||||
Object target = bean.get();
|
||||
|
||||
invokeBeanInitializationHooks(beanName, target);
|
||||
|
||||
if (bean instanceof ComponentsRegistration) {
|
||||
Map<Object, String> componentsToRegister = ((ComponentsRegistration) bean).getComponentsToRegister();
|
||||
if (!CollectionUtils.isEmpty(componentsToRegister)) {
|
||||
@@ -299,6 +322,38 @@ public class IntegrationFlowBeanPostProcessor
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeBeanInitializationHooks(final String beanName, final Object bean) {
|
||||
if (bean instanceof Aware) {
|
||||
if (bean instanceof BeanNameAware) {
|
||||
((BeanNameAware) bean).setBeanName(beanName);
|
||||
}
|
||||
if (bean instanceof BeanClassLoaderAware) {
|
||||
((BeanClassLoaderAware) bean).setBeanClassLoader(this.beanFactory.getBeanClassLoader());
|
||||
}
|
||||
if (bean instanceof BeanFactoryAware) {
|
||||
((BeanFactoryAware) bean).setBeanFactory(this.beanFactory);
|
||||
}
|
||||
if (bean instanceof EnvironmentAware) {
|
||||
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
|
||||
}
|
||||
if (bean instanceof EmbeddedValueResolverAware) {
|
||||
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
|
||||
}
|
||||
if (bean instanceof ResourceLoaderAware) {
|
||||
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
|
||||
}
|
||||
if (bean instanceof ApplicationEventPublisherAware) {
|
||||
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
|
||||
}
|
||||
if (bean instanceof MessageSourceAware) {
|
||||
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
|
||||
}
|
||||
if (bean instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerComponent(Object component, String beanName) {
|
||||
registerComponent(component, beanName, null);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2018 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.
|
||||
@@ -19,7 +19,9 @@ package org.springframework.integration.dsl;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
@@ -33,7 +35,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
* @since 5.0
|
||||
*/
|
||||
public abstract class IntegrationComponentSpec<S extends IntegrationComponentSpec<S, T>, T>
|
||||
implements FactoryBean<T> {
|
||||
implements FactoryBean<T>, InitializingBean, DisposableBean {
|
||||
|
||||
protected final static SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
@@ -83,6 +85,20 @@ public abstract class IntegrationComponentSpec<S extends IntegrationComponentSpe
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.target instanceof InitializingBean) {
|
||||
((InitializingBean) this.target).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (this.target instanceof DisposableBean) {
|
||||
((DisposableBean) this.target).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final S _this() {
|
||||
return (S) this;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2018 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.dsl.lifecycle;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.dsl.IntegrationComponentSpec;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.0.7
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@DirtiesContext
|
||||
public class IntegrationComponentSpecLifecycleTests {
|
||||
|
||||
@Autowired
|
||||
private MyComponent myComponent;
|
||||
|
||||
@Test
|
||||
public void testIntegrationComponentSpecLifecycle() {
|
||||
assertThat(this.myComponent.initialized).isTrue();
|
||||
assertThat(this.myComponent.name).isEqualTo("testSpec");
|
||||
assertThat(this.myComponent.applicationContext).isNotNull();
|
||||
assertThat(this.myComponent.beanFactory).isNotNull();
|
||||
assertThat(this.myComponent.applicationEventPublisher).isNotNull();
|
||||
assertThat(this.myComponent.classLoader).isNotNull();
|
||||
assertThat(this.myComponent.environment).isNotNull();
|
||||
assertThat(this.myComponent.messageSource).isNotNull();
|
||||
assertThat(this.myComponent.resolver).isNotNull();
|
||||
assertThat(this.myComponent.resourceLoader).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
public static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public IntegrationComponentSpec<?, ?> testSpec() {
|
||||
return new MyIntegrationComponentSpec();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class MyIntegrationComponentSpec
|
||||
extends IntegrationComponentSpec<MyIntegrationComponentSpec, MyComponent> {
|
||||
|
||||
MyIntegrationComponentSpec() {
|
||||
this.target = new MyComponent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class MyComponent
|
||||
implements InitializingBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware,
|
||||
BeanClassLoaderAware, EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware,
|
||||
ApplicationEventPublisherAware, MessageSourceAware {
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private String name;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private StringValueResolver resolver;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmbeddedValueResolver(StringValueResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user