Skip to content

Commit 1043b00

Browse files
artembilangaryrussell
authored andcommitted
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**
1 parent 76877b9 commit 1043b00

File tree

3 files changed

+254
-10
lines changed

3 files changed

+254
-10
lines changed

spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationComponentSpec.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 the original author or authors.
2+
* Copyright 2016-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,9 @@
1919
import org.apache.commons.logging.Log;
2020
import org.apache.commons.logging.LogFactory;
2121

22+
import org.springframework.beans.factory.DisposableBean;
2223
import org.springframework.beans.factory.FactoryBean;
24+
import org.springframework.beans.factory.InitializingBean;
2325
import org.springframework.expression.spel.standard.SpelExpressionParser;
2426

2527
/**
@@ -33,7 +35,7 @@
3335
* @since 5.0
3436
*/
3537
public abstract class IntegrationComponentSpec<S extends IntegrationComponentSpec<S, T>, T>
36-
implements FactoryBean<T> {
38+
implements FactoryBean<T>, InitializingBean, DisposableBean {
3739

3840
protected final static SpelExpressionParser PARSER = new SpelExpressionParser();
3941

@@ -83,6 +85,20 @@ public boolean isSingleton() {
8385
return true;
8486
}
8587

88+
@Override
89+
public void afterPropertiesSet() throws Exception {
90+
if (this.target instanceof InitializingBean) {
91+
((InitializingBean) this.target).afterPropertiesSet();
92+
}
93+
}
94+
95+
@Override
96+
public void destroy() throws Exception {
97+
if (this.target instanceof DisposableBean) {
98+
((DisposableBean) this.target).destroy();
99+
}
100+
}
101+
86102
@SuppressWarnings("unchecked")
87103
protected final S _this() {
88104
return (S) this;

spring-integration-core/src/main/java/org/springframework/integration/dsl/context/IntegrationFlowBeanPostProcessor.java

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,30 @@
2323
import org.springframework.aop.framework.ProxyFactory;
2424
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
2525
import org.springframework.beans.BeansException;
26+
import org.springframework.beans.factory.Aware;
27+
import org.springframework.beans.factory.BeanClassLoaderAware;
2628
import org.springframework.beans.factory.BeanCreationNotAllowedException;
2729
import org.springframework.beans.factory.BeanFactory;
2830
import org.springframework.beans.factory.BeanFactoryAware;
2931
import org.springframework.beans.factory.BeanFactoryUtils;
32+
import org.springframework.beans.factory.BeanNameAware;
3033
import org.springframework.beans.factory.SmartInitializingSingleton;
3134
import org.springframework.beans.factory.config.BeanDefinition;
3235
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
3336
import org.springframework.beans.factory.config.BeanPostProcessor;
3437
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
38+
import org.springframework.beans.factory.config.EmbeddedValueResolver;
3539
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3640
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3741
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
42+
import org.springframework.context.ApplicationContext;
43+
import org.springframework.context.ApplicationContextAware;
44+
import org.springframework.context.ApplicationEventPublisherAware;
45+
import org.springframework.context.ConfigurableApplicationContext;
46+
import org.springframework.context.EmbeddedValueResolverAware;
47+
import org.springframework.context.EnvironmentAware;
48+
import org.springframework.context.MessageSourceAware;
49+
import org.springframework.context.ResourceLoaderAware;
3850
import org.springframework.context.SmartLifecycle;
3951
import org.springframework.core.io.DescriptiveResource;
4052
import org.springframework.integration.channel.AbstractMessageChannel;
@@ -60,6 +72,7 @@
6072
import org.springframework.util.Assert;
6173
import org.springframework.util.CollectionUtils;
6274
import org.springframework.util.StringUtils;
75+
import org.springframework.util.StringValueResolver;
6376

6477
/**
6578
* A {@link BeanPostProcessor} to parse {@link IntegrationFlow} beans and
@@ -72,20 +85,26 @@
7285
* @since 5.0
7386
*/
7487
public class IntegrationFlowBeanPostProcessor
75-
implements BeanPostProcessor, BeanFactoryAware, SmartInitializingSingleton {
88+
implements BeanPostProcessor, ApplicationContextAware, SmartInitializingSingleton {
89+
90+
private ConfigurableApplicationContext applicationContext;
91+
92+
private StringValueResolver embeddedValueResolver;
7693

7794
private ConfigurableListableBeanFactory beanFactory;
7895

7996
private IntegrationFlowContext flowContext;
8097

8198
@Override
82-
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
83-
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
84-
"To use Spring Integration Java DSL the 'beanFactory' has to be an instance of " +
85-
"'ConfigurableListableBeanFactory'. Consider using 'GenericApplicationContext' implementation."
99+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
100+
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext,
101+
"To use Spring Integration Java DSL the 'applicationContext' has to be an instance of " +
102+
"'ConfigurableApplicationContext'. Consider using 'GenericApplicationContext' implementation."
86103
);
87104

88-
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
105+
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
106+
this.beanFactory = this.applicationContext.getBeanFactory();
107+
this.embeddedValueResolver = new EmbeddedValueResolver(this.beanFactory);
89108
this.flowContext = this.beanFactory.getBean(IntegrationFlowContext.class);
90109
Assert.notNull(this.flowContext, "There must be an IntegrationFlowContext in the application context");
91110
}
@@ -99,7 +118,7 @@ else if (bean instanceof IntegrationFlow) {
99118
return processIntegrationFlowImpl((IntegrationFlow) bean, beanName);
100119
}
101120
if (bean instanceof IntegrationComponentSpec) {
102-
processIntegrationComponentSpec((IntegrationComponentSpec<?, ?>) bean);
121+
processIntegrationComponentSpec(beanName, (IntegrationComponentSpec<?, ?>) bean);
103122
}
104123
return bean;
105124
}
@@ -316,7 +335,11 @@ private Object processIntegrationFlowImpl(IntegrationFlow flow, String beanName)
316335
}
317336
}
318337

319-
private void processIntegrationComponentSpec(IntegrationComponentSpec<?, ?> bean) {
338+
private void processIntegrationComponentSpec(String beanName, IntegrationComponentSpec<?, ?> bean) {
339+
Object target = bean.get();
340+
341+
invokeBeanInitializationHooks(beanName, target);
342+
320343
if (bean instanceof ComponentsRegistration) {
321344
Map<Object, String> componentsToRegister = ((ComponentsRegistration) bean).getComponentsToRegister();
322345
if (!CollectionUtils.isEmpty(componentsToRegister)) {
@@ -335,6 +358,38 @@ private void processIntegrationComponentSpec(IntegrationComponentSpec<?, ?> bean
335358
}
336359
}
337360

361+
private void invokeBeanInitializationHooks(final String beanName, final Object bean) {
362+
if (bean instanceof Aware) {
363+
if (bean instanceof BeanNameAware) {
364+
((BeanNameAware) bean).setBeanName(beanName);
365+
}
366+
if (bean instanceof BeanClassLoaderAware) {
367+
((BeanClassLoaderAware) bean).setBeanClassLoader(this.beanFactory.getBeanClassLoader());
368+
}
369+
if (bean instanceof BeanFactoryAware) {
370+
((BeanFactoryAware) bean).setBeanFactory(this.beanFactory);
371+
}
372+
if (bean instanceof EnvironmentAware) {
373+
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
374+
}
375+
if (bean instanceof EmbeddedValueResolverAware) {
376+
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
377+
}
378+
if (bean instanceof ResourceLoaderAware) {
379+
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
380+
}
381+
if (bean instanceof ApplicationEventPublisherAware) {
382+
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
383+
}
384+
if (bean instanceof MessageSourceAware) {
385+
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
386+
}
387+
if (bean instanceof ApplicationContextAware) {
388+
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
389+
}
390+
}
391+
}
392+
338393
private void registerComponent(Object component, String beanName) {
339394
registerComponent(component, beanName, null);
340395
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.dsl.lifecycle;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
24+
import org.springframework.beans.BeansException;
25+
import org.springframework.beans.factory.BeanClassLoaderAware;
26+
import org.springframework.beans.factory.BeanFactory;
27+
import org.springframework.beans.factory.BeanFactoryAware;
28+
import org.springframework.beans.factory.BeanNameAware;
29+
import org.springframework.beans.factory.InitializingBean;
30+
import org.springframework.beans.factory.annotation.Autowired;
31+
import org.springframework.context.ApplicationContext;
32+
import org.springframework.context.ApplicationContextAware;
33+
import org.springframework.context.ApplicationEventPublisher;
34+
import org.springframework.context.ApplicationEventPublisherAware;
35+
import org.springframework.context.EmbeddedValueResolverAware;
36+
import org.springframework.context.EnvironmentAware;
37+
import org.springframework.context.MessageSource;
38+
import org.springframework.context.MessageSourceAware;
39+
import org.springframework.context.ResourceLoaderAware;
40+
import org.springframework.context.annotation.Bean;
41+
import org.springframework.context.annotation.Configuration;
42+
import org.springframework.core.env.Environment;
43+
import org.springframework.core.io.ResourceLoader;
44+
import org.springframework.integration.config.EnableIntegration;
45+
import org.springframework.integration.dsl.IntegrationComponentSpec;
46+
import org.springframework.test.annotation.DirtiesContext;
47+
import org.springframework.test.context.junit4.SpringRunner;
48+
import org.springframework.util.StringValueResolver;
49+
50+
/**
51+
* @author Artem Bilan
52+
*
53+
* @since 5.0.7
54+
*/
55+
@RunWith(SpringRunner.class)
56+
@DirtiesContext
57+
public class IntegrationComponentSpecLifecycleTests {
58+
59+
@Autowired
60+
private MyComponent myComponent;
61+
62+
@Test
63+
public void testIntegrationComponentSpecLifecycle() {
64+
assertThat(this.myComponent.initialized).isTrue();
65+
assertThat(this.myComponent.name).isEqualTo("testSpec");
66+
assertThat(this.myComponent.applicationContext).isNotNull();
67+
assertThat(this.myComponent.beanFactory).isNotNull();
68+
assertThat(this.myComponent.applicationEventPublisher).isNotNull();
69+
assertThat(this.myComponent.classLoader).isNotNull();
70+
assertThat(this.myComponent.environment).isNotNull();
71+
assertThat(this.myComponent.messageSource).isNotNull();
72+
assertThat(this.myComponent.resolver).isNotNull();
73+
assertThat(this.myComponent.resourceLoader).isNotNull();
74+
}
75+
76+
@Configuration
77+
@EnableIntegration
78+
public static class ContextConfiguration {
79+
80+
@Bean
81+
public IntegrationComponentSpec<?, ?> testSpec() {
82+
return new MyIntegrationComponentSpec();
83+
}
84+
85+
}
86+
87+
private static final class MyIntegrationComponentSpec
88+
extends IntegrationComponentSpec<MyIntegrationComponentSpec, MyComponent> {
89+
90+
MyIntegrationComponentSpec() {
91+
this.target = new MyComponent();
92+
}
93+
94+
}
95+
96+
private static final class MyComponent
97+
implements InitializingBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware,
98+
BeanClassLoaderAware, EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware,
99+
ApplicationEventPublisherAware, MessageSourceAware {
100+
101+
private boolean initialized;
102+
103+
private ClassLoader classLoader;
104+
105+
private BeanFactory beanFactory;
106+
107+
private String name;
108+
109+
private ApplicationContext applicationContext;
110+
111+
private ApplicationEventPublisher applicationEventPublisher;
112+
113+
private StringValueResolver resolver;
114+
115+
private Environment environment;
116+
117+
private MessageSource messageSource;
118+
119+
private ResourceLoader resourceLoader;
120+
121+
@Override
122+
public void setBeanClassLoader(ClassLoader classLoader) {
123+
this.classLoader = classLoader;
124+
}
125+
126+
@Override
127+
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
128+
this.beanFactory = beanFactory;
129+
}
130+
131+
@Override
132+
public void setBeanName(String name) {
133+
this.name = name;
134+
}
135+
136+
@Override
137+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
138+
this.applicationContext = applicationContext;
139+
}
140+
141+
@Override
142+
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
143+
this.applicationEventPublisher = applicationEventPublisher;
144+
}
145+
146+
@Override
147+
public void setEmbeddedValueResolver(StringValueResolver resolver) {
148+
this.resolver = resolver;
149+
}
150+
151+
@Override
152+
public void setEnvironment(Environment environment) {
153+
this.environment = environment;
154+
}
155+
156+
@Override
157+
public void setMessageSource(MessageSource messageSource) {
158+
this.messageSource = messageSource;
159+
}
160+
161+
@Override
162+
public void setResourceLoader(ResourceLoader resourceLoader) {
163+
this.resourceLoader = resourceLoader;
164+
}
165+
166+
@Override
167+
public void afterPropertiesSet() {
168+
this.initialized = true;
169+
}
170+
171+
}
172+
173+
}

0 commit comments

Comments
 (0)