Skip to content

Commit 9ed2b03

Browse files
committed
Deffer Messaging annotations process
The `AbstractMethodAnnotationPostProcessor` and its implementations have a `beanFactory.getBean()` call for the `@Bean` methods with Messaging annotations. This is done, actually, from the `MessagingAnnotationPostProcessor.postProcessAfterInitialization()` which might be still too early in some scenarios, like Spring Cloud Feign with its child application contexts being initialized from the `FeignClientFactoryBean`, causing a `BeanCurrentlyInCreationException` See https://stackoverflow.com/questions/54887963/beancurrentlyincreationexception-when-using-spring-integration-with-spring-cloud * Implement a `SmartInitializingSingleton` for the `MessagingAnnotationPostProcessor` and gather `Runnable` wrappers for newly introduced `postProcessMethodAndRegisterEndpointIfAny()` to be called later in the `afterSingletonsInstantiated()` when context is still in the initialization phase. All runtime-registered beans are going to be processed normally from the regular `postProcessAfterInitialization()`
1 parent f741724 commit 9ed2b03

File tree

1 file changed

+56
-25
lines changed

1 file changed

+56
-25
lines changed

spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -18,6 +18,7 @@
1818

1919
import java.lang.annotation.Annotation;
2020
import java.lang.reflect.Method;
21+
import java.util.ArrayList;
2122
import java.util.Collections;
2223
import java.util.HashMap;
2324
import java.util.HashSet;
@@ -36,6 +37,7 @@
3637
import org.springframework.beans.factory.BeanFactory;
3738
import org.springframework.beans.factory.BeanFactoryAware;
3839
import org.springframework.beans.factory.InitializingBean;
40+
import org.springframework.beans.factory.SmartInitializingSingleton;
3941
import org.springframework.beans.factory.config.BeanPostProcessor;
4042
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
4143
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -71,7 +73,8 @@
7173
* @author Gary Russell
7274
* @author Rick Hogge
7375
*/
74-
public class MessagingAnnotationPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean {
76+
public class MessagingAnnotationPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean,
77+
SmartInitializingSingleton {
7578

7679
protected final Log logger = LogFactory.getLog(this.getClass()); // NOSONAR
7780

@@ -81,6 +84,10 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
8184

8285
private final Set<Class<?>> noAnnotationsCache = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
8386

87+
private final List<Runnable> methodsToPostProcessAfterContextInitialization = new ArrayList<>();
88+
89+
private volatile boolean initialized;
90+
8491
@Override
8592
public void setBeanFactory(BeanFactory beanFactory) {
8693
Assert.isAssignable(ConfigurableListableBeanFactory.class, beanFactory.getClass(),
@@ -125,6 +132,12 @@ public <A extends Annotation> void addMessagingAnnotationPostProcessor(Class<A>
125132
this.postProcessors.put(annotation, postProcessor);
126133
}
127134

135+
@Override
136+
public void afterSingletonsInstantiated() {
137+
this.initialized = true;
138+
this.methodsToPostProcessAfterContextInitialization.forEach(Runnable::run);
139+
}
140+
128141
@Override
129142
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
130143
return bean;
@@ -173,6 +186,7 @@ public Object postProcessAfterInitialization(final Object bean, final String bea
173186

174187
protected void processAnnotationTypeOnMethod(Object bean, String beanName, Method method,
175188
Class<? extends Annotation> annotationType, List<Annotation> annotations) {
189+
176190
MethodAnnotationPostProcessor<?> postProcessor =
177191
MessagingAnnotationPostProcessor.this.postProcessors.get(annotationType);
178192
if (postProcessor != null && postProcessor.shouldCreateEndpoint(method, annotations)) {
@@ -187,36 +201,53 @@ protected void processAnnotationTypeOnMethod(Object bean, String beanName, Metho
187201
+ "and its method: '" + method + "'", e);
188202
}
189203
}
190-
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
191-
if (result != null && result instanceof AbstractEndpoint) {
192-
AbstractEndpoint endpoint = (AbstractEndpoint) result;
193-
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
194-
String.class);
204+
205+
if (this.initialized) {
206+
postProcessMethodAndRegisterEndpointIfAny(bean, beanName, method, annotationType, annotations,
207+
postProcessor, targetMethod);
208+
}
209+
else {
210+
Method methodToPostProcess = targetMethod;
211+
this.methodsToPostProcessAfterContextInitialization.add(() ->
212+
postProcessMethodAndRegisterEndpointIfAny(bean, beanName, method, annotationType, annotations,
213+
postProcessor, methodToPostProcess));
214+
}
215+
}
216+
}
217+
218+
private void postProcessMethodAndRegisterEndpointIfAny(Object bean, String beanName, Method method,
219+
Class<? extends Annotation> annotationType, List<Annotation> annotations,
220+
MethodAnnotationPostProcessor<?> postProcessor, Method targetMethod) {
221+
222+
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
223+
if (result instanceof AbstractEndpoint) {
224+
AbstractEndpoint endpoint = (AbstractEndpoint) result;
225+
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
226+
String.class);
227+
if (StringUtils.hasText(autoStartup)) {
228+
autoStartup = getBeanFactory().resolveEmbeddedValue(autoStartup);
195229
if (StringUtils.hasText(autoStartup)) {
196-
autoStartup = getBeanFactory().resolveEmbeddedValue(autoStartup);
197-
if (StringUtils.hasText(autoStartup)) {
198-
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
199-
}
230+
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
200231
}
232+
}
201233

202-
String phase = MessagingAnnotationUtils.resolveAttribute(annotations, "phase", String.class);
234+
String phase = MessagingAnnotationUtils.resolveAttribute(annotations, "phase", String.class);
235+
if (StringUtils.hasText(phase)) {
236+
phase = getBeanFactory().resolveEmbeddedValue(phase);
203237
if (StringUtils.hasText(phase)) {
204-
phase = getBeanFactory().resolveEmbeddedValue(phase);
205-
if (StringUtils.hasText(phase)) {
206-
endpoint.setPhase(Integer.parseInt(phase));
207-
}
208-
}
209-
210-
Role role = AnnotationUtils.findAnnotation(method, Role.class);
211-
if (role != null) {
212-
endpoint.setRole(role.value());
238+
endpoint.setPhase(Integer.parseInt(phase));
213239
}
240+
}
214241

215-
String endpointBeanName = generateBeanName(beanName, method, annotationType);
216-
endpoint.setBeanName(endpointBeanName);
217-
getBeanFactory().registerSingleton(endpointBeanName, endpoint);
218-
getBeanFactory().initializeBean(endpoint, endpointBeanName);
242+
Role role = AnnotationUtils.findAnnotation(method, Role.class);
243+
if (role != null) {
244+
endpoint.setRole(role.value());
219245
}
246+
247+
String endpointBeanName = generateBeanName(beanName, method, annotationType);
248+
endpoint.setBeanName(endpointBeanName);
249+
getBeanFactory().registerSingleton(endpointBeanName, endpoint);
250+
getBeanFactory().initializeBean(endpoint, endpointBeanName);
220251
}
221252
}
222253

0 commit comments

Comments
 (0)