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:
Artem Bilan
2021-11-01 10:25:38 -04:00
committed by GitHub
parent ff3b4d34a1
commit f520156053
3 changed files with 84 additions and 67 deletions

View File

@@ -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");
}

View File

@@ -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();

View File

@@ -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;
}
}
}