Uploaded image for project: 'Spring Integration'
  1. Spring Integration
  2. INT-3009

Consider Removing 'Dangling' Handler Bean Definitions

    XMLWordPrintable

Details

    • Improvement
    • Status: Open
    • Minor
    • Resolution: Unresolved
    • 3.0 M1
    • General Backlog
    • Core
    • None

    Description

      When a consumer endpoint is re-defined, the ConsumerEndpointFactoryBean definition is correctly overridden; however, the handler bean definition is left as a 'hanging' bean definition that has no references.

      Consider removing such definitions with something like...

      diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java
      index 805a90b..6fdf0d4 100644
      --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java
      +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java
      @@ -19,14 +19,19 @@ package org.springframework.integration.config.xml;
       import java.util.Collection;
       import java.util.List;
       
      +import org.w3c.dom.Element;
      +
      +import org.springframework.beans.PropertyValue;
       import org.springframework.beans.factory.BeanDefinitionStoreException;
       import org.springframework.beans.factory.config.BeanDefinition;
       import org.springframework.beans.factory.config.ConstructorArgumentValues;
       import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
      +import org.springframework.beans.factory.config.RuntimeBeanReference;
       import org.springframework.beans.factory.parsing.BeanComponentDefinition;
       import org.springframework.beans.factory.support.AbstractBeanDefinition;
       import org.springframework.beans.factory.support.BeanDefinitionBuilder;
       import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
      +import org.springframework.beans.factory.support.BeanDefinitionRegistry;
       import org.springframework.beans.factory.support.ManagedSet;
       import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
       import org.springframework.beans.factory.xml.ParserContext;
      @@ -34,7 +39,6 @@ import org.springframework.integration.config.ConsumerEndpointFactoryBean;
       import org.springframework.util.CollectionUtils;
       import org.springframework.util.StringUtils;
       import org.springframework.util.xml.DomUtils;
      -import org.w3c.dom.Element;
       
       /**
        * Base class parser for elements that create Message Endpoints.
      @@ -55,10 +59,7 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
       	@Override
       	protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
       			throws BeanDefinitionStoreException {
      -		String id = element.getAttribute(ID_ATTRIBUTE);
      -		if (!StringUtils.hasText(id)) {
      -			id = element.getAttribute("name");
      -		}
      +		String id = obtainId(element);
       		if (!StringUtils.hasText(id)) {
       			id = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry(), parserContext.isNested());
       		}
      @@ -74,8 +75,28 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
       		return "input-channel";
       	}
       
      +	private String obtainId(Element element) {
      +		String id = element.getAttribute(ID_ATTRIBUTE);
      +		if (!StringUtils.hasText(id)) {
      +			id = element.getAttribute("name");
      +		}
      +		return id;
      +	}
      +
       	@Override
       	protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
      +		String id = obtainId(element);
      +		BeanDefinitionRegistry registry = parserContext.getRegistry();
      +		if (StringUtils.hasText(id)) {
      +			if (registry.containsBeanDefinition(id)){
      +				BeanDefinition oldBeanDefinition = registry.getBeanDefinition(id);
      +				PropertyValue handlerProperty = oldBeanDefinition.getPropertyValues().getPropertyValue("handler");
      +				if (handlerProperty.getValue() instanceof RuntimeBeanReference) {
      +					String handlerBeanName = ((RuntimeBeanReference) handlerProperty.getValue()).getBeanName();
      +					registry.removeBeanDefinition(handlerBeanName);
      +				}
      +			}
      +		}
       		BeanDefinitionBuilder handlerBuilder = this.parseHandler(element, parserContext);
       		IntegrationNamespaceUtils.setReferenceIfAttributeDefined(handlerBuilder, element, "output-channel");
       		IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "order");
      

      However, see INT-2755 (chain), where the chain parser needs the definition to remain so it can remove any registered chain beans. So, the removal of the stale handler definition needs to be deferred until after the handler has been parsed.

      But, that adds a further complication in that the generated bean names will out of whack.

      Perhaps this should be combined with doing away with generic bean name generation for handlers, and use the "consumer.handler" name as the child name instead of adding it as an alias.

      Attachments

        Issue Links

          Activity

            People

              abilan Artem Bilan
              grussell Gary Russell
              Votes:
              1 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated: