diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractStandardMessageHandlerFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractStandardMessageHandlerFactoryBean.java index 084a3d0572..ceac102ab8 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractStandardMessageHandlerFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractStandardMessageHandlerFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -21,6 +21,7 @@ import java.util.Set; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.Advised; +import org.springframework.beans.factory.DisposableBean; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; @@ -41,21 +42,23 @@ import org.springframework.util.StringUtils; * @author David Liu */ public abstract class AbstractStandardMessageHandlerFactoryBean - extends AbstractSimpleMessageHandlerFactoryBean { + extends AbstractSimpleMessageHandlerFactoryBean implements DisposableBean { private static final ExpressionParser expressionParser = new SpelExpressionParser(); private static final Set referencedReplyProducers = new HashSet<>(); - private volatile Boolean requiresReply; + private Boolean requiresReply; - private volatile Object targetObject; + private Object targetObject; - private volatile String targetMethodName; + private String targetMethodName; - private volatile Expression expression; + private Expression expression; - private volatile Long sendTimeout; + private Long sendTimeout; + + private MessageHandler replyHandler; /** * Set the target POJO for the message handler. @@ -101,6 +104,13 @@ public abstract class AbstractStandardMessageHandlerFactoryBean return this.sendTimeout; } + @Override + public void destroy() { + if (this.replyHandler != null) { + referencedReplyProducers.remove(this.replyHandler); + } + } + @Override protected MessageHandler createHandler() { MessageHandler handler; @@ -158,6 +168,7 @@ public abstract class AbstractStandardMessageHandlerFactoryBean "An AbstractMessageProducingMessageHandler may only be referenced once (" + replyHandler.getComponentName() + ") - use scope=\"prototype\""); referencedReplyProducers.add(replyHandler); + this.replyHandler = replyHandler; } /** diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java index 414ed2a482..f9fb6bd2d7 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java @@ -29,7 +29,9 @@ import org.reactivestreams.Publisher; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.aggregator.AggregatingMessageHandler; @@ -120,9 +122,9 @@ public abstract class IntegrationFlowDefinition integrationComponents = new LinkedHashMap<>(); - protected MessageChannel currentMessageChannel; + private MessageChannel currentMessageChannel; - protected Object currentComponent; + private Object currentComponent; private StandardIntegrationFlow integrationFlow; @@ -479,7 +481,9 @@ public abstract class IntegrationFlowDefinition> endpointConfigurer) { + public B transform(String expression, + Consumer> endpointConfigurer) { + Assert.hasText(expression, "'expression' must not be empty"); return transform(new ExpressionEvaluatingTransformer(PARSER.parseExpression(expression)), endpointConfigurer); @@ -2771,4 +2775,21 @@ public abstract class IntegrationFlowDefinition replyProducers = + TestUtils.getPropertyValue(flowBuilder, "REFERENCED_REPLY_PRODUCERS", Set.class); + + assertTrue(replyProducers.contains(bridgeHandler)); + flowRegistration.destroy(); + + assertFalse(replyProducers.contains(bridgeHandler)); } @Test @@ -184,12 +202,13 @@ public class ManualFlowTests { .addBean(additionalBean) .register(); + String flowRegistrationId = flowRegistration.getId(); BeanFactoryHandler bean = - this.beanFactory.getBean(flowRegistration.getId() + BeanFactoryHandler.class.getName() + "#0", + this.beanFactory.getBean(flowRegistrationId + BeanFactoryHandler.class.getName() + "#0", BeanFactoryHandler.class); assertSame(additionalBean, bean); assertSame(this.beanFactory, bean.beanFactory); - bean = this.beanFactory.getBean(flowRegistration.getId() + "." + "anId.handler", BeanFactoryHandler.class); + bean = this.beanFactory.getBean(flowRegistrationId + "." + "anId.handler", BeanFactoryHandler.class); MessagingTemplate messagingTemplate = flowRegistration.getMessagingTemplate(); messagingTemplate.setReceiveTimeout(10000); @@ -211,9 +230,9 @@ public class ManualFlowTests { flowRegistration.destroy(); - assertFalse(this.beanFactory.containsBean(flowRegistration.getId())); - assertFalse(this.beanFactory.containsBean(flowRegistration.getId() + ".input")); - assertFalse(this.beanFactory.containsBean(flowRegistration.getId() + BeanFactoryHandler.class.getName() + "#0")); + assertFalse(this.beanFactory.containsBean(flowRegistrationId)); + assertFalse(this.beanFactory.containsBean(flowRegistrationId + ".input")); + assertFalse(this.beanFactory.containsBean(flowRegistrationId + BeanFactoryHandler.class.getName() + "#0")); ThreadPoolTaskScheduler taskScheduler = this.beanFactory.getBean(ThreadPoolTaskScheduler.class);