Skip to content

Commit

Permalink
GH-3653: Improve DSL parsing performance (#3654)
Browse files Browse the repository at this point in the history
* GH-3653: Improve DSL parsing performance

Fixes #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`
  • Loading branch information
artembilan committed Nov 1, 2021
1 parent ff3b4d3 commit f520156
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -18,7 +18,6 @@

import java.util.Map;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.integration.channel.DirectChannel;

/**
Expand Down Expand Up @@ -78,8 +77,7 @@ public StandardIntegrationFlow get() {
this.inputChannel);
}

private static class StandardIntegrationFlowExtension extends StandardIntegrationFlow
implements BeanNameAware {
private static class StandardIntegrationFlowExtension extends StandardIntegrationFlow {

private final DirectChannel inputChannel;

Expand All @@ -90,6 +88,7 @@ private static class StandardIntegrationFlowExtension extends StandardIntegratio

@Override
public void setBeanName(String name) {
super.setBeanName(name);
this.inputChannel.setBeanName(name + ".input");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -24,7 +24,9 @@
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;

/**
Expand Down Expand Up @@ -65,18 +67,36 @@
* @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;

private MessageChannel inputChannel;

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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,49 @@ else if (useFlowIdAsPrefix) {
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) {
Expand All @@ -191,14 +234,6 @@ else if (useFlowIdAsPrefix) {
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();
Expand All @@ -209,47 +244,12 @@ else if (component instanceof FixedSubscriberChannel) {
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);
}
Expand Down Expand Up @@ -396,26 +396,24 @@ private void invokeBeanInitializationHooks(final String beanName, final Object b
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))) {

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;
}
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 true;
return false;
}
}
}
Expand Down

0 comments on commit f520156

Please sign in to comment.