This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new 3f48269562 Adds a new completion state to the deployer (#13340)
3f48269562 is described below

commit 3f48269562bda8cba9a7b50b35757ae80c3826a3
Author: TomlongTK <[email protected]>
AuthorDate: Wed Nov 29 20:58:43 2023 +0800

    Adds a new completion state to the deployer (#13340)
    
    * Adjust the order of events in Deployer
    
    * Format code
    
    * Add completion state
    
    * Format code
    
    * Format code
    
    * Format code
    
    * Marking completion as final state
    
    * Add some comments
    
    * Add some comments
    
    * Fix application state calculate
    
    * Compatible with started state
    
    * Fix tests
---
 .../dubbo/common/deploy/AbstractDeployer.java      |  26 ++++-
 .../apache/dubbo/common/deploy/DeployListener.java |  22 ++++
 .../dubbo/common/deploy/DeployListenerAdapter.java |   3 +
 .../apache/dubbo/common/deploy/DeployState.java    |   5 +
 .../org/apache/dubbo/common/deploy/Deployer.java   |   2 +
 .../dubbo/config/bootstrap/DubboBootstrap.java     |  16 +--
 .../config/deploy/DefaultApplicationDeployer.java  | 121 ++++++++++++---------
 .../dubbo/config/deploy/DefaultModuleDeployer.java |  19 +++-
 .../config/metadata/ExporterDeployListener.java    |   3 +
 .../dubbo/config/bootstrap/DubboBootstrapTest.java |   2 +-
 .../dubbo/config/bootstrap/MultiInstanceTest.java  |  41 ++++---
 ...RegistryCenterDubboProtocolIntegrationTest.java |  23 ++--
 .../context/DubboDeployApplicationListener.java    |  10 ++
 .../context/KeepRunningOnSpringClosedTest.java     |  18 +--
 .../qos/probe/impl/DeployerReadinessProbe.java     |   2 +-
 .../apache/dubbo/qos/command/impl/ReadyTest.java   |   4 +-
 .../dubbo/security/cert/CertDeployerListener.java  |   3 +
 17 files changed, 218 insertions(+), 102 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/AbstractDeployer.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/AbstractDeployer.java
index 554f7f9c85..9d48f48224 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/AbstractDeployer.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/AbstractDeployer.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import static 
org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_MONITOR_EXCEPTION;
+import static org.apache.dubbo.common.deploy.DeployState.COMPLETION;
 import static org.apache.dubbo.common.deploy.DeployState.FAILED;
 import static org.apache.dubbo.common.deploy.DeployState.PENDING;
 import static org.apache.dubbo.common.deploy.DeployState.STARTED;
@@ -56,12 +57,17 @@ public abstract class AbstractDeployer<E extends 
ScopeModel> implements Deployer
 
     @Override
     public boolean isRunning() {
-        return state == STARTING || state == STARTED;
+        return state == STARTING || state == STARTED || state == COMPLETION;
     }
 
     @Override
     public boolean isStarted() {
-        return state == STARTED;
+        return state == STARTED || state == COMPLETION;
+    }
+
+    @Override
+    public boolean isCompletion() {
+        return state == COMPLETION;
     }
 
     @Override
@@ -135,6 +141,22 @@ public abstract class AbstractDeployer<E extends 
ScopeModel> implements Deployer
         }
     }
 
+    protected void setCompletion() {
+        this.state = COMPLETION;
+        for (DeployListener<E> listener : listeners) {
+            try {
+                listener.onCompletion(scopeModel);
+            } catch (Throwable e) {
+                logger.error(
+                        COMMON_MONITOR_EXCEPTION,
+                        "",
+                        "",
+                        getIdentifier() + " an exception occurred when handle 
completion event",
+                        e);
+            }
+        }
+    }
+
     protected void setStopping() {
         this.state = STOPPING;
         for (DeployListener<E> listener : listeners) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListener.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListener.java
index b52455bbc4..a68769e6a5 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListener.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListener.java
@@ -24,13 +24,35 @@ public interface DeployListener<E extends ScopeModel> {
      */
     void onInitialize(E scopeModel);
 
+    /**
+     * Triggered before starting module.
+     */
     void onStarting(E scopeModel);
 
+    /**
+     * Triggered before registering and exposing the service.
+     */
     void onStarted(E scopeModel);
 
+    /**
+     * Triggered after deployer startup is complete.
+     */
+    default void onCompletion(E scopeModel) {}
+
+    /**
+     * Triggered before the app is destroyed,
+     * can do some customized things before offline the service and destroy 
reference.
+     */
     void onStopping(E scopeModel);
 
+    /**
+     * Triggered after the application is destroyed,
+     * can do some customized things after the service is offline and the 
reference is destroyed.
+     */
     void onStopped(E scopeModel);
 
+    /**
+     * Useful to do something when deployer was failed.
+     */
     void onFailure(E scopeModel, Throwable cause);
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListenerAdapter.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListenerAdapter.java
index 6a34b7dced..c2e06dbb62 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListenerAdapter.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListenerAdapter.java
@@ -28,6 +28,9 @@ public class DeployListenerAdapter<E extends ScopeModel> 
implements DeployListen
     @Override
     public void onStarted(E scopeModel) {}
 
+    @Override
+    public void onCompletion(E scopeModel) {}
+
     @Override
     public void onStopping(E scopeModel) {}
 
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployState.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployState.java
index 2790639a70..db43cc59ec 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployState.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployState.java
@@ -40,6 +40,11 @@ public enum DeployState {
      */
     STARTED,
 
+    /**
+     * Completion
+     */
+    COMPLETION,
+
     /**
      * Stopping
      */
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/Deployer.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/Deployer.java
index b590751b33..dadc3dae2a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/Deployer.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/Deployer.java
@@ -55,6 +55,8 @@ public interface Deployer<E extends ScopeModel> {
      */
     boolean isStarted();
 
+    boolean isCompletion();
+
     /**
      * @return true if the component is starting.
      * @see #isStarted()
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
index abb9327eac..e0ca381661 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
@@ -294,6 +294,10 @@ public final class DubboBootstrap {
         return applicationDeployer.isStarted();
     }
 
+    public boolean isCompletion() {
+        return applicationDeployer.isCompletion();
+    }
+
     /**
      * @return true if the dubbo application is stopping.
      * @see #isStopped()
@@ -524,8 +528,7 @@ public final class DubboBootstrap {
     private <S> ServiceConfig createServiceConfig(String id, 
Consumer<ServiceBuilder<S>> consumerBuilder) {
         ServiceBuilder builder = createServiceBuilder(id);
         consumerBuilder.accept(builder);
-        ServiceConfig serviceConfig = builder.build();
-        return serviceConfig;
+        return builder.build();
     }
 
     public DubboBootstrap services(List<ServiceConfig> serviceConfigs) {
@@ -561,8 +564,7 @@ public final class DubboBootstrap {
     private <S> ReferenceConfig createReferenceConfig(String id, 
Consumer<ReferenceBuilder<S>> consumerBuilder) {
         ReferenceBuilder builder = createReferenceBuilder(id);
         consumerBuilder.accept(builder);
-        ReferenceConfig referenceConfig = builder.build();
-        return referenceConfig;
+        return builder.build();
     }
 
     public DubboBootstrap references(List<ReferenceConfig> referenceConfigs) {
@@ -599,8 +601,7 @@ public final class DubboBootstrap {
     private ProviderConfig createProviderConfig(String id, 
Consumer<ProviderBuilder> builderConsumer) {
         ProviderBuilder builder = createProviderBuilder(id);
         builderConsumer.accept(builder);
-        ProviderConfig providerConfig = builder.build();
-        return providerConfig;
+        return builder.build();
     }
 
     public DubboBootstrap provider(ProviderConfig providerConfig) {
@@ -632,8 +633,7 @@ public final class DubboBootstrap {
     private ConsumerConfig createConsumerConfig(String id, 
Consumer<ConsumerBuilder> builderConsumer) {
         ConsumerBuilder builder = createConsumerBuilder(id);
         builderConsumer.accept(builder);
-        ConsumerConfig consumerConfig = builder.build();
-        return consumerConfig;
+        return builder.build();
     }
 
     public DubboBootstrap consumer(ConsumerConfig consumerConfig) {
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
index b3291a7bb2..e1e0938153 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
@@ -361,7 +361,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
         configManager.loadConfigsOfTypeFromProps(RegistryConfig.class);
 
         List<RegistryConfig> defaultRegistries = 
configManager.getDefaultRegistries();
-        if (defaultRegistries.size() > 0) {
+        if (!defaultRegistries.isEmpty()) {
             defaultRegistries.stream()
                     .filter(this::isUsedRegistryAsConfigCenter)
                     .map(this::registryAsConfigCenter)
@@ -511,9 +511,8 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
             defaultRegistries.stream()
                     .filter(this::isUsedRegistryAsMetadataCenter)
                     .map(registryConfig -> 
registryAsMetadataCenter(registryConfig, metadataConfigToOverride))
-                    .forEach(metadataReportConfig -> {
-                        overrideMetadataReportConfig(metadataConfigToOverride, 
metadataReportConfig);
-                    });
+                    .forEach(metadataReportConfig ->
+                            
overrideMetadataReportConfig(metadataConfigToOverride, metadataReportConfig));
         }
     }
 
@@ -693,7 +692,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
                 }
 
                 // if is started and no new module, just return
-                if (isStarted() && !hasPendingModule) {
+                if ((isStarted() || isCompletion()) && !hasPendingModule) {
                     return CompletableFuture.completedFuture(false);
                 }
 
@@ -812,7 +811,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
             // start internal module
             ModuleDeployer internalModuleDeployer =
                     applicationModel.getInternalModule().getDeployer();
-            if (!internalModuleDeployer.isStarted()) {
+            if (!internalModuleDeployer.isCompletion()) {
                 Future future = internalModuleDeployer.start();
                 // wait for internal module startup
                 try {
@@ -1015,7 +1014,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
 
                                 // refresh for 30 times (default for 30s) when 
deployer is not started, prevent submit
                                 // too many revision
-                                if 
(instanceRefreshScheduleTimes.incrementAndGet() % 30 != 0 && !isStarted()) {
+                                if 
(instanceRefreshScheduleTimes.incrementAndGet() % 30 != 0 && !isCompletion()) {
                                     return;
                                 }
 
@@ -1190,6 +1189,9 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
                 case STARTED:
                     onStarted();
                     break;
+                case COMPLETION:
+                    onCompletion();
+                    break;
                 case STARTING:
                     onStarting();
                     break;
@@ -1221,8 +1223,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
     }
 
     private DeployState calculateState() {
-        DeployState newState = DeployState.UNKNOWN;
-        int pending = 0, starting = 0, started = 0, stopping = 0, stopped = 0, 
failed = 0;
+        int total = 0, pending = 0, starting = 0, started = 0, completion = 0, 
stopping = 0, stopped = 0, failed = 0;
         for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
             ModuleDeployer deployer = moduleModel.getDeployer();
             if (deployer == null) {
@@ -1231,6 +1232,8 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
                 pending++;
             } else if (deployer.isStarting()) {
                 starting++;
+            } else if (deployer.isCompletion()) {
+                completion++;
             } else if (deployer.isStarted()) {
                 started++;
             } else if (deployer.isStopping()) {
@@ -1240,39 +1243,37 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
             } else if (deployer.isFailed()) {
                 failed++;
             }
+            total++;
         }
-
+        // any module is failed
         if (failed > 0) {
-            newState = DeployState.FAILED;
-        } else if (started > 0) {
-            if (pending + starting + stopping + stopped == 0) {
-                // all modules have been started
-                newState = DeployState.STARTED;
-            } else if (pending + starting > 0) {
-                // some module is pending and some is started
-                newState = DeployState.STARTING;
-            } else if (stopping + stopped > 0) {
-                newState = DeployState.STOPPING;
-            }
-        } else if (starting > 0) {
-            // any module is starting
-            newState = DeployState.STARTING;
-        } else if (pending > 0) {
-            if (starting + starting + stopping + stopped == 0) {
-                // all modules have not starting or started
-                newState = DeployState.PENDING;
-            } else if (stopping + stopped > 0) {
-                // some is pending and some is stopping or stopped
-                newState = DeployState.STOPPING;
-            }
-        } else if (stopping > 0) {
-            // some is stopping and some stopped
-            newState = DeployState.STOPPING;
-        } else if (stopped > 0) {
-            // all modules are stopped
-            newState = DeployState.STOPPED;
+            return DeployState.FAILED;
+        }
+        // all modules have not starting or started
+        if (pending == total) {
+            return DeployState.PENDING;
         }
-        return newState;
+        // all modules have completed
+        if (completion == total) {
+            return DeployState.COMPLETION;
+        }
+        // all modules are stopped
+        if (stopped == total) {
+            return DeployState.STOPPED;
+        }
+        // some module is starting or pending, it's in starting state
+        if (starting > 0 || pending > 0) {
+            return DeployState.STARTING;
+        }
+        // some module is stopping or stopped, it's in stopping state
+        if (stopping > 0 || stopped > 0) {
+            return DeployState.STOPPING;
+        }
+        // all modules have been started
+        if (started > 0) {
+            return DeployState.STARTED;
+        }
+        return DeployState.UNKNOWN;
     }
 
     private void onInitialize() {
@@ -1291,7 +1292,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
     }
 
     private void doExportMetadataService() {
-        if (!isStarting() && !isStarted()) {
+        if (!isStarting() && !isStarted() && !isCompletion()) {
             return;
         }
         for (DeployListener<ApplicationModel> listener : listeners) {
@@ -1313,7 +1314,8 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
     private void onStarting() {
         // pending -> starting
         // started -> starting
-        if (!(isPending() || isStarted())) {
+        // completion -> starting
+        if (!(isPending() || isStarted() || isCompletion())) {
             return;
         }
         setStarting();
@@ -1324,23 +1326,34 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
     }
 
     private void onStarted() {
+        // starting -> started
+        if (!isStarting()) {
+            return;
+        }
+        setStarted();
+        startMetricsCollector();
+        if (logger.isInfoEnabled()) {
+            logger.info(getIdentifier() + " is ready.");
+        }
+        // refresh metadata
+        try {
+            if (registered) {
+                
ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);
+            }
+        } catch (Exception e) {
+            logger.error(CONFIG_REFRESH_INSTANCE_ERROR, "", "", "Refresh 
instance and metadata error.", e);
+        }
+    }
+
+    private void onCompletion() {
         try {
-            // starting -> started
-            if (!isStarting()) {
+            // started -> completion
+            if (!isStarted()) {
                 return;
             }
-            setStarted();
-            startMetricsCollector();
+            setCompletion();
             if (logger.isInfoEnabled()) {
-                logger.info(getIdentifier() + " is ready.");
-            }
-            // refresh metadata
-            try {
-                if (registered) {
-                    
ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);
-                }
-            } catch (Exception e) {
-                logger.error(CONFIG_REFRESH_INSTANCE_ERROR, "", "", "Refresh 
instance and metadata error.", e);
+                logger.info(getIdentifier() + " has completed.");
             }
         } finally {
             // complete future
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java
index 0722ff2c7e..1cc0744dc0 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java
@@ -165,7 +165,7 @@ public class DefaultModuleDeployer extends 
AbstractDeployer<ModuleModel> impleme
         }
 
         try {
-            if (isStarting() || isStarted()) {
+            if (isStarting() || isStarted() || isCompletion()) {
                 return startFuture;
             }
 
@@ -196,6 +196,9 @@ public class DefaultModuleDeployer extends 
AbstractDeployer<ModuleModel> impleme
                 // check reference config
                 checkReferences();
 
+                // publish module completion event
+                onModuleCompletion();
+
                 // complete module start future after application state changed
                 completeStartFuture(true);
             } else {
@@ -203,6 +206,7 @@ public class DefaultModuleDeployer extends 
AbstractDeployer<ModuleModel> impleme
                     try {
                         // wait for export finish
                         waitExportFinish();
+
                         // wait for refer finish
                         waitReferFinish();
 
@@ -214,6 +218,9 @@ public class DefaultModuleDeployer extends 
AbstractDeployer<ModuleModel> impleme
 
                         // check reference config
                         checkReferences();
+
+                        // publish module completion event
+                        onModuleCompletion();
                     } catch (Throwable e) {
                         logger.warn(
                                 CONFIG_FAILED_WAIT_EXPORT_REFER,
@@ -243,7 +250,7 @@ public class DefaultModuleDeployer extends 
AbstractDeployer<ModuleModel> impleme
     }
 
     private boolean hasExportedServices() {
-        return configManager.getServices().size() > 0;
+        return !configManager.getServices().isEmpty();
     }
 
     @Override
@@ -367,6 +374,14 @@ public class DefaultModuleDeployer extends 
AbstractDeployer<ModuleModel> impleme
         }
     }
 
+    private void onModuleCompletion() {
+        if (isStarted()) {
+            setCompletion();
+            logger.info(getIdentifier() + " has completed.");
+            applicationDeployer.notifyModuleChanged(moduleModel, 
DeployState.COMPLETION);
+        }
+    }
+
     private void onModuleFailed(String msg, Throwable ex) {
         try {
             try {
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ExporterDeployListener.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ExporterDeployListener.java
index b5819892bd..e9ede45636 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ExporterDeployListener.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ExporterDeployListener.java
@@ -39,6 +39,9 @@ public class ExporterDeployListener implements 
ApplicationDeployListener, Priori
     @Override
     public synchronized void onStarted(ApplicationModel applicationModel) {}
 
+    @Override
+    public void onCompletion(ApplicationModel scopeModel) {}
+
     @Override
     public synchronized void onStopping(ApplicationModel scopeModel) {}
 
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
index 73c258e1fc..2d4c1e625a 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
@@ -264,7 +264,7 @@ class DubboBootstrapTest {
                 .start();
 
         Assertions.assertTrue(bootstrap.isInitialized());
-        Assertions.assertTrue(bootstrap.isStarted());
+        Assertions.assertTrue(bootstrap.isCompletion());
         Assertions.assertFalse(bootstrap.isStopped());
 
         ApplicationModel applicationModel = bootstrap.getApplicationModel();
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java
index 1aa652dca6..c09e2a17e1 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java
@@ -25,6 +25,7 @@ import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigKeys;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.RegistryConfig;
@@ -32,6 +33,7 @@ import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.SysProps;
 import org.apache.dubbo.config.api.DemoService;
 import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.config.context.ConfigMode;
 import org.apache.dubbo.config.mock.GreetingLocal2;
 import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
 import org.apache.dubbo.registry.client.migration.MigrationInvoker;
@@ -475,10 +477,10 @@ class MultiInstanceTest {
 
             ModuleDeployer moduleDeployer1 = 
serviceConfig1.getScopeModel().getDeployer();
             moduleDeployer1.start().get();
-            Assertions.assertTrue(moduleDeployer1.isStarted());
+            Assertions.assertTrue(moduleDeployer1.isCompletion());
             ModuleDeployer internalModuleDeployer =
                     applicationModel.getInternalModule().getDeployer();
-            Assertions.assertTrue(internalModuleDeployer.isStarted());
+            Assertions.assertTrue(internalModuleDeployer.isCompletion());
 
             FrameworkServiceRepository frameworkServiceRepository =
                     
applicationModel.getFrameworkModel().getServiceRepository();
@@ -606,7 +608,7 @@ class MultiInstanceTest {
             // 1. start module1 and wait
             ModuleDeployer moduleDeployer1 = 
serviceConfig1.getScopeModel().getDeployer();
             moduleDeployer1.start().get();
-            Assertions.assertEquals(DeployState.STARTED, 
moduleDeployer1.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
moduleDeployer1.getState());
 
             ApplicationModel applicationModel = 
providerBootstrap.getApplicationModel();
             ApplicationDeployer applicationDeployer = 
applicationModel.getDeployer();
@@ -617,9 +619,9 @@ class MultiInstanceTest {
 
             // 2. start application after module1 is started
             providerBootstrap.start();
-            Assertions.assertEquals(DeployState.STARTED, 
applicationDeployer.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
applicationDeployer.getState());
             Assertions.assertEquals(
-                    DeployState.STARTED, 
defaultModule.getDeployer().getState());
+                    DeployState.COMPLETION, 
defaultModule.getDeployer().getState());
 
             // 3. add module2 and re-start application
             ServiceConfig serviceConfig2 = new ServiceConfig();
@@ -629,9 +631,9 @@ class MultiInstanceTest {
             ModuleModel moduleModel2 =
                     
providerBootstrap.newModule().service(serviceConfig2).getModuleModel();
             providerBootstrap.start();
-            Assertions.assertEquals(DeployState.STARTED, 
applicationDeployer.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
applicationDeployer.getState());
             Assertions.assertEquals(
-                    DeployState.STARTED, 
moduleModel2.getDeployer().getState());
+                    DeployState.COMPLETION, 
moduleModel2.getDeployer().getState());
 
             // 4. add module3 and start module3
             ServiceConfig serviceConfig3 = new ServiceConfig();
@@ -641,9 +643,9 @@ class MultiInstanceTest {
             ModuleModel moduleModel3 =
                     
providerBootstrap.newModule().service(serviceConfig3).getModuleModel();
             moduleModel3.getDeployer().start().get();
-            Assertions.assertEquals(DeployState.STARTED, 
applicationDeployer.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
applicationDeployer.getState());
             Assertions.assertEquals(
-                    DeployState.STARTED, 
moduleModel3.getDeployer().getState());
+                    DeployState.COMPLETION, 
moduleModel3.getDeployer().getState());
 
         } finally {
             if (providerBootstrap != null) {
@@ -697,10 +699,10 @@ class MultiInstanceTest {
 
             // 2. start application after module1 is starting
             providerBootstrap.start();
-            Assertions.assertEquals(DeployState.STARTED, 
applicationDeployer.getState());
-            Assertions.assertEquals(DeployState.STARTED, 
moduleDeployer1.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
applicationDeployer.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
moduleDeployer1.getState());
             Assertions.assertEquals(
-                    DeployState.STARTED, 
defaultModule.getDeployer().getState());
+                    DeployState.COMPLETION, 
defaultModule.getDeployer().getState());
 
         } finally {
             if (providerBootstrap != null) {
@@ -713,6 +715,7 @@ class MultiInstanceTest {
     void testOldApiDeploy() throws Exception {
 
         try {
+            SysProps.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, 
ConfigMode.OVERRIDE.name());
             // provider app
             ApplicationModel providerApplicationModel = 
ApplicationModel.defaultModel();
             ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
@@ -731,17 +734,19 @@ class MultiInstanceTest {
             Map<DeployState, Long> serviceDeployEventMap = 
serviceDeployEventHandler.deployEventMap;
             
Assertions.assertFalse(serviceDeployEventMap.containsKey(DeployState.STARTING));
             
Assertions.assertFalse(serviceDeployEventMap.containsKey(DeployState.STARTED));
+            
Assertions.assertFalse(serviceDeployEventMap.containsKey(DeployState.COMPLETION));
 
             // export service and start module
             serviceConfig.export();
             // expect internal module is started
             Assertions.assertTrue(
-                    
providerApplicationModel.getInternalModule().getDeployer().isStarted());
+                    
providerApplicationModel.getInternalModule().getDeployer().isCompletion());
             // expect service module is starting
             
Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.STARTING));
             // wait for service module started
             serviceConfig.getScopeModel().getDeployer().getStartFuture().get();
             
Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.STARTED));
+            
Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.COMPLETION));
 
             // consumer app
             ApplicationModel consumerApplicationModel = 
ApplicationModel.defaultModel();
@@ -760,16 +765,18 @@ class MultiInstanceTest {
             Map<DeployState, Long> deployEventMap = 
referDeployEventHandler.deployEventMap;
             
Assertions.assertFalse(deployEventMap.containsKey(DeployState.STARTING));
             
Assertions.assertFalse(deployEventMap.containsKey(DeployState.STARTED));
+            
Assertions.assertFalse(deployEventMap.containsKey(DeployState.COMPLETION));
 
             // get ref proxy and start module
             DemoService demoService = referenceConfig.get();
             // expect internal module is started
             Assertions.assertTrue(
-                    
consumerApplicationModel.getInternalModule().getDeployer().isStarted());
+                    
consumerApplicationModel.getInternalModule().getDeployer().isCompletion());
             
Assertions.assertTrue(deployEventMap.containsKey(DeployState.STARTING));
             // wait for reference module started
             
referenceConfig.getScopeModel().getDeployer().getStartFuture().get();
             
Assertions.assertTrue(deployEventMap.containsKey(DeployState.STARTED));
+            
Assertions.assertTrue(deployEventMap.containsKey(DeployState.COMPLETION));
 
             // stop consumer app
             consumerApplicationModel.destroy();
@@ -919,6 +926,12 @@ class MultiInstanceTest {
             deployEventMap.put(DeployState.STARTED, 
System.currentTimeMillis());
         }
 
+        @Override
+        public void onCompletion(ModuleModel scopeModel) {
+            Assertions.assertEquals(moduleModel, scopeModel);
+            deployEventMap.put(DeployState.COMPLETION, 
System.currentTimeMillis());
+        }
+
         @Override
         public void onStopping(ModuleModel scopeModel) {
             Assertions.assertEquals(moduleModel, scopeModel);
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
index 5f668f48a2..56ad379ea1 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
@@ -151,7 +151,7 @@ class SingleRegistryCenterDubboProtocolIntegrationTest 
implements IntegrationTes
         // ServiceConfig is exported or not
         Assertions.assertFalse(serviceConfig.isExported());
         // ServiceConfig's exportedUrl has values or not
-        Assertions.assertEquals(serviceConfig.getExportedUrls().size(), 0);
+        Assertions.assertEquals(0, serviceConfig.getExportedUrls().size());
         // DubboBootstrap is pending or not
         Assertions.assertTrue(DubboBootstrap.getInstance().isPending());
         // DubboBootstrap is initialized or not
@@ -195,13 +195,15 @@ class SingleRegistryCenterDubboProtocolIntegrationTest 
implements IntegrationTes
         // DubboBootstrap is pending or not
         Assertions.assertFalse(DubboBootstrap.getInstance().isPending());
         // DubboBootstrap is started or not
-        Assertions.assertTrue(DubboBootstrap.getInstance().isStarted());
+        Assertions.assertTrue(DubboBootstrap.getInstance().isCompletion());
+        // DubboBootstrap is running
+        Assertions.assertTrue(DubboBootstrap.getInstance().isRunning());
         // DubboBootstrap is shutdown or not
         Assertions.assertFalse(DubboBootstrap.getInstance().isStopped());
         // Service has been exported or not
         Assertions.assertTrue(this.serviceConfig.isExported());
         // There is exported urls or not
-        Assertions.assertEquals(this.serviceConfig.getExportedUrls().size(), 
1);
+        Assertions.assertEquals(1, 
this.serviceConfig.getExportedUrls().size());
         URL exportedUrl = this.serviceConfig.getExportedUrls().get(0);
         // Protocol name is right or not
         Assertions.assertEquals(exportedUrl.getProtocol(), PROTOCOL_NAME);
@@ -231,7 +233,7 @@ class SingleRegistryCenterDubboProtocolIntegrationTest 
implements IntegrationTes
                 
serviceConfig.getScopeModel().getBeanFactory().getBean(MetadataService.class);
         // Exported url is right or not in InMemoryWritableMetadataService
         Assertions.assertEquals(
-                inMemoryWritableMetadataService.getExportedURLs().size(), 1);
+                1, inMemoryWritableMetadataService.getExportedURLs().size());
         // MetadataInfo exists or not in InMemoryWritableMetadataService
         Assertions.assertFalse(
                 inMemoryWritableMetadataService.getMetadataInfos().isEmpty());
@@ -243,12 +245,12 @@ class SingleRegistryCenterDubboProtocolIntegrationTest 
implements IntegrationTes
                 .isEmpty());
         // MetadataInfo has reported or not has service or not
         Assertions.assertEquals(
+                1,
                 inMemoryWritableMetadataService
                         .getMetadataInfos()
                         .get(0)
                         .getServices()
-                        .size(),
-                1);
+                        .size());
         // obtain the service's key
         String key = SingleRegistryCenterIntegrationService.class.getName() + 
":" + PROTOCOL_NAME;
         MetadataInfo.ServiceInfo serviceInfo = inMemoryWritableMetadataService
@@ -278,10 +280,10 @@ class SingleRegistryCenterDubboProtocolIntegrationTest 
implements IntegrationTes
                 
ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension("exported");
         Assertions.assertNotNull(singleRegistryCenterExportedServiceListener);
         Assertions.assertEquals(
+                1,
                 singleRegistryCenterExportedServiceListener
                         .getExportedServices()
-                        .size(),
-                1);
+                        .size());
         Assertions.assertEquals(
                 SingleRegistryCenterIntegrationService.class,
                 singleRegistryCenterExportedServiceListener
@@ -382,12 +384,13 @@ class SingleRegistryCenterDubboProtocolIntegrationTest 
implements IntegrationTes
         
Assertions.assertTrue(serviceDiscoveryRegistryDirectory.isShouldRegister());
         // ServiceDiscoveryRegistryDirectory's registered consumer url is 
right or not
         Assertions.assertEquals(
-                
serviceDiscoveryRegistryDirectory.getRegisteredConsumerUrl().getCategory(), 
CONSUMERS_CATEGORY);
+                CONSUMERS_CATEGORY,
+                
serviceDiscoveryRegistryDirectory.getRegisteredConsumerUrl().getCategory());
         // ServiceDiscoveryRegistryDirectory's registry is right or not
         Assertions.assertTrue(serviceDiscoveryRegistryDirectory.getRegistry() 
instanceof ListenerRegistryWrapper);
         // Directory's invokers are right or not
         Assertions.assertEquals(
-                serviceDiscoveryRegistryDirectory.getAllInvokers().size(), 1);
+                1, serviceDiscoveryRegistryDirectory.getAllInvokers().size());
         Assertions.assertEquals(
                 serviceDiscoveryRegistryDirectory.getInvokers(), 
serviceDiscoveryRegistryDirectory.getAllInvokers());
     }
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java
 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java
index 869e61b9fb..a52246bf90 100644
--- 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java
+++ 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java
@@ -77,6 +77,11 @@ public class DubboDeployApplicationListener
                 publishApplicationEvent(DeployState.STARTED);
             }
 
+            @Override
+            public void onCompletion(ApplicationModel scopeModel) {
+                publishApplicationEvent(DeployState.COMPLETION);
+            }
+
             @Override
             public void onStopping(ApplicationModel scopeModel) {
                 publishApplicationEvent(DeployState.STOPPING);
@@ -103,6 +108,11 @@ public class DubboDeployApplicationListener
                 publishModuleEvent(DeployState.STARTED);
             }
 
+            @Override
+            public void onCompletion(ModuleModel scopeModel) {
+                publishModuleEvent(DeployState.COMPLETION);
+            }
+
             @Override
             public void onStopping(ModuleModel scopeModel) {
                 publishModuleEvent(DeployState.STOPPING);
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/KeepRunningOnSpringClosedTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/KeepRunningOnSpringClosedTest.java
index 4d1fe654b8..afcf4140e4 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/KeepRunningOnSpringClosedTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/KeepRunningOnSpringClosedTest.java
@@ -49,17 +49,18 @@ class KeepRunningOnSpringClosedTest {
             // No need check and wait
 
             DubboStateListener dubboStateListener = 
providerContext.getBean(DubboStateListener.class);
-            Assertions.assertEquals(DeployState.STARTED, 
dubboStateListener.getState());
+            Assertions.assertEquals(DeployState.COMPLETION, 
dubboStateListener.getState());
 
             ModuleModel moduleModel = 
providerContext.getBean(ModuleModel.class);
             ModuleDeployer moduleDeployer = moduleModel.getDeployer();
-            Assertions.assertTrue(moduleDeployer.isStarted());
+            Assertions.assertTrue(moduleDeployer.isCompletion());
 
             ApplicationDeployer applicationDeployer =
                     moduleModel.getApplicationModel().getDeployer();
-            Assertions.assertEquals(DeployState.STARTED, 
applicationDeployer.getState());
-            Assertions.assertEquals(true, applicationDeployer.isStarted());
-            Assertions.assertEquals(false, applicationDeployer.isStopped());
+            Assertions.assertEquals(DeployState.COMPLETION, 
applicationDeployer.getState());
+            Assertions.assertTrue(applicationDeployer.isCompletion());
+            Assertions.assertTrue(applicationDeployer.isStarted());
+            Assertions.assertFalse(applicationDeployer.isStopped());
             
Assertions.assertNotNull(DubboSpringInitializer.findBySpringContext(providerContext));
 
             // close spring context
@@ -67,9 +68,10 @@ class KeepRunningOnSpringClosedTest {
 
             // Expect 2: dubbo application will not be destroyed after closing 
spring context cause
             // setKeepRunningOnSpringClosed(true)
-            Assertions.assertEquals(DeployState.STARTED, 
applicationDeployer.getState());
-            Assertions.assertEquals(true, applicationDeployer.isStarted());
-            Assertions.assertEquals(false, applicationDeployer.isStopped());
+            Assertions.assertEquals(DeployState.COMPLETION, 
applicationDeployer.getState());
+            Assertions.assertTrue(applicationDeployer.isCompletion());
+            Assertions.assertTrue(applicationDeployer.isStarted());
+            Assertions.assertFalse(applicationDeployer.isStopped());
             
Assertions.assertNull(DubboSpringInitializer.findBySpringContext(providerContext));
         } finally {
             DubboBootstrap.getInstance().stop();
diff --git 
a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/DeployerReadinessProbe.java
 
b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/DeployerReadinessProbe.java
index 4121c399a7..2f5c0c1e24 100644
--- 
a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/DeployerReadinessProbe.java
+++ 
b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/DeployerReadinessProbe.java
@@ -40,7 +40,7 @@ public class DeployerReadinessProbe implements ReadinessProbe 
{
         List<ApplicationModel> applicationModels = 
frameworkModel.getApplicationModels();
         for (ApplicationModel applicationModel : applicationModels) {
             for (ModuleModel moduleModel : applicationModel.getModuleModels()) 
{
-                if (!moduleModel.getDeployer().isStarted()) {
+                if (!moduleModel.getDeployer().isCompletion()) {
                     return false;
                 }
             }
diff --git 
a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ReadyTest.java
 
b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ReadyTest.java
index 0be0567b12..9d95f9ac97 100644
--- 
a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ReadyTest.java
+++ 
b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ReadyTest.java
@@ -63,7 +63,7 @@ class ReadyTest {
         
Mockito.when(applicationModel.getModuleModels()).thenReturn(Arrays.asList(moduleModel));
         
Mockito.when(applicationModel.getApplicationConfigManager()).thenReturn(manager);
         Mockito.when(moduleModel.getDeployer()).thenReturn(moduleDeployer);
-        Mockito.when(moduleDeployer.isStarted()).thenReturn(true);
+        Mockito.when(moduleDeployer.isCompletion()).thenReturn(true);
 
         ExtensionLoader loader = Mockito.mock(ExtensionLoader.class);
         
Mockito.when(frameworkModel.getExtensionLoader(ReadinessProbe.class)).thenReturn(loader);
@@ -83,7 +83,7 @@ class ReadyTest {
         Assertions.assertEquals("true", result);
         Assertions.assertEquals(commandContext.getHttpCode(), 200);
 
-        Mockito.when(moduleDeployer.isStarted()).thenReturn(false);
+        Mockito.when(moduleDeployer.isCompletion()).thenReturn(false);
         result = ready.execute(commandContext, new String[0]);
         Assertions.assertEquals("false", result);
         Assertions.assertEquals(commandContext.getHttpCode(), 503);
diff --git 
a/dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertDeployerListener.java
 
b/dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertDeployerListener.java
index 13ba78e41e..2a8ab6e735 100644
--- 
a/dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertDeployerListener.java
+++ 
b/dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertDeployerListener.java
@@ -49,6 +49,9 @@ public class CertDeployerListener implements 
ApplicationDeployListener {
     @Override
     public void onStarted(ApplicationModel scopeModel) {}
 
+    @Override
+    public void onCompletion(ApplicationModel scopeModel) {}
+
     @Override
     public void onStopping(ApplicationModel scopeModel) {
         if (dubboCertManager != null) {


Reply via email to