From be98a6c2d0a89b57d9a328b0a3cbb722152cc485 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 15 May 2017 20:03:46 -0400 Subject: [PATCH] INT-4274: Improve IntegrationFlow Lifecycle JIRA: https://jira.spring.io/browse/INT-4274 Since any component from the `StandardIntegrationFlow` can be started independently, the `StandardIntegrationFlow.stop()` should propagate the stop control to the target components independently of its previous `running` state Javadoc Polishing --- .../integration/dsl/IntegrationFlow.java | 9 ++- .../dsl/StandardIntegrationFlow.java | 68 +++++++++++++------ 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlow.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlow.java index cc309c6592..8513daf7b3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlow.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlow.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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,7 +21,7 @@ package org.springframework.integration.dsl; *

* The {@link StandardIntegrationFlow} implementation (produced by {@link IntegrationFlowBuilder}) * represents a container for the integration components, which will be registered - * in the application context. Typically is used as {@code @Bean} definition: + * in the application context. Typically is used as a {@code @Bean} definition: *

  *  @Bean
  *  public IntegrationFlow fileReadingFlow() {
@@ -73,6 +73,11 @@ package org.springframework.integration.dsl;
 @FunctionalInterface
 public interface IntegrationFlow {
 
+	/**
+	 * The callback-based function to declare the chain of EIP-methods to
+	 * configure an integration flow with the provided {@link IntegrationFlowDefinition}.
+	 * @param flow the {@link IntegrationFlowDefinition} to configure
+	 */
 	void configure(IntegrationFlowDefinition flow);
 
 }
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/StandardIntegrationFlow.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/StandardIntegrationFlow.java
index 9ea711f730..2960c04c88 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/StandardIntegrationFlow.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/StandardIntegrationFlow.java
@@ -25,22 +25,54 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.springframework.context.SmartLifecycle;
 
 /**
+ * The standard implementation of the {@link IntegrationFlow} interface instantiated
+ * by the Framework. Represents a logical container for the components configured
+ * for the integration flow. It can be treated as a single component, especially
+ * when declaring dynamically, using the
+ * {@link org.springframework.integration.dsl.context.IntegrationFlowContext}.
+ * 

+ * Being the logical container for the target integration components, this class controls + * the lifecycle of all those components, when its {@code start()} and {@code stop()} are + * invoked. + *

+ * This component is never {@code autoStartup}, because all the components are + * registered as beans in the application context and their initial start up phase is + * controlled from the lifecycle processor automatically. + *

+ * However, when we register an {@link IntegrationFlow} dynamically using the + * {@link org.springframework.integration.dsl.context.IntegrationFlowContext} API, + * the lifecycle processor from the application context is not involved; + * therefore we should control the lifecyle of the beans manually, or rely on the + * {@link org.springframework.integration.dsl.context.IntegrationFlowContext} API. + * Its created registration is {@code autoStartup} by default and + * starts the flow when it is registered. If you disable the registration's auto- + * startup behavior, you are responsible for starting the flow or its component + * beans. + *

+ * This component doesn't track its {@code running} state during {@code stop()} action + * and delegates directly to stop the registered components, to avoid dangling processes + * after a registered {@link IntegrationFlow} is removed from the flow context. + * * @author Artem Bilan * * @since 5.0 + * + * @see IntegrationFlows + * @see org.springframework.integration.config.dsl.IntegrationFlowBeanPostProcessor + * @see org.springframework.integration.dsl.context.IntegrationFlowContext */ public class StandardIntegrationFlow implements IntegrationFlow, SmartLifecycle { private final List integrationComponents; - private final List lifecycles = new LinkedList(); + private final List lifecycles = new LinkedList<>(); private final boolean registerComponents = true; // NOSONAR private boolean running; StandardIntegrationFlow(Set integrationComponents) { - this.integrationComponents = new LinkedList(integrationComponents); + this.integrationComponents = new LinkedList<>(integrationComponents); } //TODO Figure out some custom DestinationResolver when we don't register singletons - remove NOSONAR above when done @@ -84,31 +116,27 @@ public class StandardIntegrationFlow implements IntegrationFlow, SmartLifecycle @Override public void stop(Runnable callback) { - if (this.running) { - AggregatingCallback aggregatingCallback = new AggregatingCallback(this.lifecycles.size(), callback); - ListIterator iterator = this.lifecycles.listIterator(this.lifecycles.size()); - while (iterator.hasPrevious()) { - SmartLifecycle lifecycle = iterator.previous(); - if (lifecycle.isRunning()) { - lifecycle.stop(aggregatingCallback); - } - else { - aggregatingCallback.run(); - } + AggregatingCallback aggregatingCallback = new AggregatingCallback(this.lifecycles.size(), callback); + ListIterator iterator = this.lifecycles.listIterator(this.lifecycles.size()); + while (iterator.hasPrevious()) { + SmartLifecycle lifecycle = iterator.previous(); + if (lifecycle.isRunning()) { + lifecycle.stop(aggregatingCallback); + } + else { + aggregatingCallback.run(); } - this.running = false; } + this.running = false; } @Override public void stop() { - if (this.running) { - ListIterator iterator = this.lifecycles.listIterator(this.lifecycles.size()); - while (iterator.hasPrevious()) { - iterator.previous().stop(); - } - this.running = false; + ListIterator iterator = this.lifecycles.listIterator(this.lifecycles.size()); + while (iterator.hasPrevious()) { + iterator.previous().stop(); } + this.running = false; } @Override