From f520156053cc6e8abe10e1605f35f2db0f1f9f63 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 1 Nov 2021 10:25:38 -0400 Subject: [PATCH] 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` --- .../dsl/IntegrationFlowExtension.java | 7 +- .../dsl/StandardIntegrationFlow.java | 24 +++- .../IntegrationFlowBeanPostProcessor.java | 120 +++++++++--------- 3 files changed, 84 insertions(+), 67 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowExtension.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowExtension.java index 3bbcf34e2b..483fa23155 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowExtension.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowExtension.java @@ -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 integrationComponents; @@ -73,10 +76,27 @@ public class StandardIntegrationFlow implements IntegrationFlow, SmartLifecycle private boolean running; + private String beanName; + StandardIntegrationFlow(Map 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(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/context/IntegrationFlowBeanPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/context/IntegrationFlowBeanPostProcessor.java index 8e2649e822..b341d4031c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/context/IntegrationFlowBeanPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/context/IntegrationFlowBeanPostProcessor.java @@ -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 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 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) instance.getClass(), - () -> instance) - .getBeanDefinition(); - beanDefinition.setResourceDescription("the '" + parentBeanName + "' bean definition"); - throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingBeanDefinition); - } - else { - return false; - } + AbstractBeanDefinition beanDefinition = + BeanDefinitionBuilder.genericBeanDefinition((Class) instance.getClass(), + () -> instance) + .getBeanDefinition(); + beanDefinition.setResourceDescription("the '" + parentBeanName + "' bean definition"); + throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingBeanDefinition); } else { - return true; + return false; } } }