GH-3653: Improve DSL parsing performance (#3654)
* GH-3653: Improve DSL parsing performance Fixes https://github.com/spring-projects/spring-integration/issues/3653 * Refactor `IntegrationFlowBeanPostProcessor` to perform `beanFactory.getBeansOfType()` as less as possible * Implement a `NamedComponent` on the `StandardIntegrationFlow` for better bean scanning performance in the `IntegrationFlowBeanPostProcessor` * * Skip `NamedComponent` from bean scanning if `beanName == null`
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
* Copyright 2020-2021 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.integration.dsl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
|
||||
/**
|
||||
@@ -78,8 +77,7 @@ public abstract class IntegrationFlowExtension<B extends IntegrationFlowExtensio
|
||||
this.inputChannel);
|
||||
}
|
||||
|
||||
private static class StandardIntegrationFlowExtension extends StandardIntegrationFlow
|
||||
implements BeanNameAware {
|
||||
private static class StandardIntegrationFlowExtension extends StandardIntegrationFlow {
|
||||
|
||||
private final DirectChannel inputChannel;
|
||||
|
||||
@@ -90,6 +88,7 @@ public abstract class IntegrationFlowExtension<B extends IntegrationFlowExtensio
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
super.setBeanName(name);
|
||||
this.inputChannel.setBeanName(name + ".input");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
* Copyright 2016-2021 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.
|
||||
@@ -24,7 +24,9 @@ import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.integration.support.context.NamedComponent;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
@@ -65,7 +67,8 @@ import org.springframework.messaging.MessageChannel;
|
||||
* @see org.springframework.integration.dsl.context.IntegrationFlowContext
|
||||
* @see SmartLifecycle
|
||||
*/
|
||||
public class StandardIntegrationFlow implements IntegrationFlow, SmartLifecycle {
|
||||
public class StandardIntegrationFlow
|
||||
implements IntegrationFlow, SmartLifecycle, BeanNameAware, NamedComponent {
|
||||
|
||||
private final Map<Object, String> integrationComponents;
|
||||
|
||||
@@ -73,10 +76,27 @@ public class StandardIntegrationFlow implements IntegrationFlow, SmartLifecycle
|
||||
|
||||
private boolean running;
|
||||
|
||||
private String beanName;
|
||||
|
||||
StandardIntegrationFlow(Map<Object, String> integrationComponents) {
|
||||
this.integrationComponents = new LinkedHashMap<>(integrationComponents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "integration-flow";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(IntegrationFlowDefinition<?> flow) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
@@ -177,6 +177,49 @@ public class IntegrationFlowBeanPostProcessor
|
||||
registerComponent(endpoint, id, flowBeanName);
|
||||
targetIntegrationComponents.put(endpoint, id);
|
||||
}
|
||||
else if (component instanceof MessageChannelReference) {
|
||||
String channelBeanName = ((MessageChannelReference) component).getName();
|
||||
if (!this.beanFactory.containsBean(channelBeanName)) {
|
||||
DirectChannel directChannel = new DirectChannel();
|
||||
registerComponent(directChannel, channelBeanName, flowBeanName);
|
||||
targetIntegrationComponents.put(directChannel, channelBeanName);
|
||||
}
|
||||
}
|
||||
else if (component instanceof SourcePollingChannelAdapterSpec) {
|
||||
SourcePollingChannelAdapterSpec spec = (SourcePollingChannelAdapterSpec) component;
|
||||
Map<Object, String> componentsToRegister = spec.getComponentsToRegister();
|
||||
if (!CollectionUtils.isEmpty(componentsToRegister)) {
|
||||
componentsToRegister.entrySet()
|
||||
.stream()
|
||||
.filter(o -> noBeanPresentForComponent(o.getKey(), flowBeanName))
|
||||
.forEach(o ->
|
||||
registerComponent(o.getKey(),
|
||||
generateBeanName(o.getKey(), flowNamePrefix, o.getValue(),
|
||||
useFlowIdAsPrefix)));
|
||||
}
|
||||
SourcePollingChannelAdapterFactoryBean pollingChannelAdapterFactoryBean = spec.get().getT1();
|
||||
String id = spec.getId();
|
||||
if (id == null) {
|
||||
id = generateBeanName(pollingChannelAdapterFactoryBean, flowNamePrefix, entry.getValue(),
|
||||
useFlowIdAsPrefix);
|
||||
}
|
||||
else if (useFlowIdAsPrefix) {
|
||||
id = flowNamePrefix + id;
|
||||
}
|
||||
|
||||
registerComponent(pollingChannelAdapterFactoryBean, id, flowBeanName);
|
||||
targetIntegrationComponents.put(pollingChannelAdapterFactoryBean, id);
|
||||
|
||||
MessageSource<?> messageSource = spec.get().getT2();
|
||||
if (noBeanPresentForComponent(messageSource, flowBeanName)) {
|
||||
String messageSourceId = id + ".source";
|
||||
if (messageSource instanceof NamedComponent
|
||||
&& ((NamedComponent) messageSource).getComponentName() != null) {
|
||||
messageSourceId = ((NamedComponent) messageSource).getComponentName();
|
||||
}
|
||||
registerComponent(messageSource, messageSourceId, flowBeanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (noBeanPresentForComponent(component, flowBeanName)) {
|
||||
if (component instanceof AbstractMessageChannel || component instanceof NullChannel) {
|
||||
@@ -191,14 +234,6 @@ public class IntegrationFlowBeanPostProcessor
|
||||
registerComponent(component, channelBeanName, flowBeanName);
|
||||
targetIntegrationComponents.put(component, channelBeanName);
|
||||
}
|
||||
else if (component instanceof MessageChannelReference) {
|
||||
String channelBeanName = ((MessageChannelReference) component).getName();
|
||||
if (!this.beanFactory.containsBean(channelBeanName)) {
|
||||
DirectChannel directChannel = new DirectChannel();
|
||||
registerComponent(directChannel, channelBeanName, flowBeanName);
|
||||
targetIntegrationComponents.put(directChannel, channelBeanName);
|
||||
}
|
||||
}
|
||||
else if (component instanceof FixedSubscriberChannel) {
|
||||
FixedSubscriberChannel fixedSubscriberChannel = (FixedSubscriberChannel) component;
|
||||
String channelBeanName = fixedSubscriberChannel.getComponentName();
|
||||
@@ -209,47 +244,12 @@ public class IntegrationFlowBeanPostProcessor
|
||||
registerComponent(component, channelBeanName, flowBeanName);
|
||||
targetIntegrationComponents.put(component, channelBeanName);
|
||||
}
|
||||
else if (component instanceof SourcePollingChannelAdapterSpec) {
|
||||
SourcePollingChannelAdapterSpec spec = (SourcePollingChannelAdapterSpec) component;
|
||||
Map<Object, String> componentsToRegister = spec.getComponentsToRegister();
|
||||
if (!CollectionUtils.isEmpty(componentsToRegister)) {
|
||||
componentsToRegister.entrySet()
|
||||
.stream()
|
||||
.filter(o -> noBeanPresentForComponent(o.getKey(), flowBeanName))
|
||||
.forEach(o ->
|
||||
registerComponent(o.getKey(),
|
||||
generateBeanName(o.getKey(), flowNamePrefix, o.getValue(),
|
||||
useFlowIdAsPrefix)));
|
||||
}
|
||||
SourcePollingChannelAdapterFactoryBean pollingChannelAdapterFactoryBean = spec.get().getT1();
|
||||
String id = spec.getId();
|
||||
if (id == null) {
|
||||
id = generateBeanName(pollingChannelAdapterFactoryBean, flowNamePrefix, entry.getValue(),
|
||||
useFlowIdAsPrefix);
|
||||
}
|
||||
else if (useFlowIdAsPrefix) {
|
||||
id = flowNamePrefix + id;
|
||||
}
|
||||
|
||||
registerComponent(pollingChannelAdapterFactoryBean, id, flowBeanName);
|
||||
targetIntegrationComponents.put(pollingChannelAdapterFactoryBean, id);
|
||||
|
||||
MessageSource<?> messageSource = spec.get().getT2();
|
||||
if (noBeanPresentForComponent(messageSource, flowBeanName)) {
|
||||
String messageSourceId = id + ".source";
|
||||
if (messageSource instanceof NamedComponent
|
||||
&& ((NamedComponent) messageSource).getComponentName() != null) {
|
||||
messageSourceId = ((NamedComponent) messageSource).getComponentName();
|
||||
}
|
||||
registerComponent(messageSource, messageSourceId, flowBeanName);
|
||||
}
|
||||
}
|
||||
else if (component instanceof StandardIntegrationFlow) {
|
||||
String subFlowBeanName =
|
||||
entry.getValue() != null
|
||||
? entry.getValue()
|
||||
: flowNamePrefix + "subFlow" +
|
||||
BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + subFlowNameIndex++;
|
||||
BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + subFlowNameIndex++;
|
||||
registerComponent(component, subFlowBeanName, flowBeanName);
|
||||
targetIntegrationComponents.put(component, subFlowBeanName);
|
||||
}
|
||||
@@ -396,26 +396,24 @@ public class IntegrationFlowBeanPostProcessor
|
||||
private boolean noBeanPresentForComponent(Object instance, String parentBeanName) {
|
||||
if (instance instanceof NamedComponent) {
|
||||
String beanName = ((NamedComponent) instance).getBeanName();
|
||||
if (beanName != null) {
|
||||
if (this.beanFactory.containsBean(beanName)) {
|
||||
BeanDefinition existingBeanDefinition =
|
||||
IntegrationContextUtils.getBeanDefinition(beanName, this.beanFactory);
|
||||
if (!ConfigurableBeanFactory.SCOPE_PROTOTYPE.equals(existingBeanDefinition.getScope())
|
||||
&& !instance.equals(this.beanFactory.getBean(beanName))) {
|
||||
if (beanName == null || !this.beanFactory.containsBean(beanName)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
BeanDefinition existingBeanDefinition =
|
||||
IntegrationContextUtils.getBeanDefinition(beanName, this.beanFactory);
|
||||
if (!ConfigurableBeanFactory.SCOPE_PROTOTYPE.equals(existingBeanDefinition.getScope())
|
||||
&& !instance.equals(this.beanFactory.getBean(beanName))) {
|
||||
|
||||
AbstractBeanDefinition beanDefinition =
|
||||
BeanDefinitionBuilder.genericBeanDefinition((Class<Object>) instance.getClass(),
|
||||
() -> instance)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.setResourceDescription("the '" + parentBeanName + "' bean definition");
|
||||
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingBeanDefinition);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
AbstractBeanDefinition beanDefinition =
|
||||
BeanDefinitionBuilder.genericBeanDefinition((Class<Object>) instance.getClass(),
|
||||
() -> instance)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.setResourceDescription("the '" + parentBeanName + "' bean definition");
|
||||
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingBeanDefinition);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user