GH-3253: Scan BF hierarchy for BeanDefinition
Fixes https://github.com/spring-projects/spring-integration/issues/3253 The `IntegrationFlowBeanPostProcessor` uses a `containsBean()` and then `getBeanDefinition()` to be sure that we don't override already existing bean even if it is created in the parent(s) context. The problem that `containsBean()` check the hierarchy, but `getBeanDefinition()` doesn't. So, we fail with `NoSuchBeanDefinitionException` if bean exists in the parent ctx * Introduce an utility `IntegrationContextUtils.getBeanDefinition()` to scan `BeanFactory` recursively for `BeanDefinition` for the requested `name` * Use this tool in the `IntegrationFlowBeanPostProcessor` logic **Cherry-pick to 5.2.x & 5.1.x**
This commit is contained in:
committed by
Gary Russell
parent
e73e08b968
commit
4092427878
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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,6 +19,9 @@ package org.springframework.integration.context;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
@@ -212,4 +215,26 @@ public abstract class IntegrationContextUtils {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link BeanDefinition} with the given name,
|
||||
* obtained from the given {@link BeanFactory} or one of its parents.
|
||||
* @param name the bean name to return
|
||||
* @param beanFactory the {@link ConfigurableListableBeanFactory} to travers.
|
||||
* @return the {@link BeanDefinition} for a given name
|
||||
* @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} is not found
|
||||
* @since 5.1.10
|
||||
*/
|
||||
public static BeanDefinition getBeanDefinition(String name, ConfigurableListableBeanFactory beanFactory) {
|
||||
try {
|
||||
return beanFactory.getBeanDefinition(name);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
|
||||
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
return getBeanDefinition(name, (ConfigurableListableBeanFactory) parentBeanFactory);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2020 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.
|
||||
@@ -57,6 +57,7 @@ import org.springframework.integration.channel.NullChannel;
|
||||
import org.springframework.integration.config.ConsumerEndpointFactoryBean;
|
||||
import org.springframework.integration.config.IntegrationConfigUtils;
|
||||
import org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.dsl.ComponentsRegistration;
|
||||
import org.springframework.integration.dsl.ConsumerEndpointSpec;
|
||||
@@ -138,7 +139,8 @@ public class IntegrationFlowBeanPostProcessor
|
||||
}
|
||||
}
|
||||
|
||||
private Object processStandardIntegrationFlow(StandardIntegrationFlow flow, String flowBeanName) { // NOSONAR complexity
|
||||
private Object processStandardIntegrationFlow(StandardIntegrationFlow flow, String flowBeanName) { // NOSONAR
|
||||
// complexity
|
||||
String flowNamePrefix = flowBeanName + ".";
|
||||
if (this.flowContext == null) {
|
||||
this.flowContext = this.beanFactory.getBean(IntegrationFlowContext.class);
|
||||
@@ -283,7 +285,9 @@ public class IntegrationFlowBeanPostProcessor
|
||||
String beanNameToUse = entry.getValue();
|
||||
if (StringUtils.hasText(beanNameToUse) &&
|
||||
ConfigurableBeanFactory.SCOPE_PROTOTYPE.equals(
|
||||
this.beanFactory.getBeanDefinition(beanNameToUse).getScope())) {
|
||||
IntegrationContextUtils.getBeanDefinition(beanNameToUse, this.beanFactory)
|
||||
.getScope())) {
|
||||
|
||||
this.beanFactory.initializeBean(componentToUse, beanNameToUse);
|
||||
}
|
||||
targetIntegrationComponents.put(component, beanNameToUse);
|
||||
@@ -393,7 +397,8 @@ public class IntegrationFlowBeanPostProcessor
|
||||
String beanName = ((NamedComponent) instance).getBeanName();
|
||||
if (beanName != null) {
|
||||
if (this.beanFactory.containsBean(beanName)) {
|
||||
BeanDefinition existingBeanDefinition = this.beanFactory.getBeanDefinition(beanName);
|
||||
BeanDefinition existingBeanDefinition =
|
||||
IntegrationContextUtils.getBeanDefinition(beanName, this.beanFactory);
|
||||
if (!ConfigurableBeanFactory.SCOPE_PROTOTYPE.equals(existingBeanDefinition.getScope())
|
||||
&& !instance.equals(this.beanFactory.getBean(beanName))) {
|
||||
|
||||
@@ -429,8 +434,8 @@ public class IntegrationFlowBeanPostProcessor
|
||||
|
||||
AbstractBeanDefinition beanDefinition =
|
||||
BeanDefinitionBuilder.genericBeanDefinition((Class<Object>) component.getClass(), () -> component)
|
||||
.applyCustomizers(customizers)
|
||||
.getRawBeanDefinition();
|
||||
.applyCustomizers(customizers)
|
||||
.getRawBeanDefinition();
|
||||
|
||||
if (parentName != null && this.beanFactory.containsBeanDefinition(parentName)) {
|
||||
AbstractBeanDefinition parentBeanDefinition =
|
||||
|
||||
Reference in New Issue
Block a user