You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/09/23 09:38:27 UTC

[dubbo] branch 3.0 updated: [3.0] improve unit test efficiency (#8877)

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

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


The following commit(s) were added to refs/heads/3.0 by this push:
     new eba466e  [3.0] improve unit test efficiency (#8877)
eba466e is described below

commit eba466e0c8959f821c6c76d888bb6a55a2dfef3c
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Thu Sep 23 17:38:19 2021 +0800

    [3.0] improve unit test efficiency (#8877)
    
    * speed up maven building, disable update snapshot, remove unnecessary repositories
    
    * reduce shutdown wait time
    
    * update maven version to fix build error such as "java.lang.IllegalStateException: Entry [id:..][route:{s}->...][state:null] has not been leased from this pool", see
     https://issues.apache.org/jira/browse/HTTPCORE-634 (httpcore 4.4.14)
    
    * add shutdown timeout for netty4
    
    * fix scope model
    
    * read server shutdown wait time before destroy
    
    * Add shutdown timeout for triple protocol
    
    * Improve register center of tests
    
    * set shutdown wait time as attribute of ProtocolServer
    
    * Fix reconnect and close
    
    * fix closePromise
---
 .mvn/wrapper/maven-wrapper.properties              |  2 +-
 .../src/test/resources/dubbo.properties            |  1 +
 .../dubbo/common/config/ConfigurationUtils.java    |  5 ++
 dubbo-common/src/test/resources/dubbo.properties   |  2 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../apache/dubbo/config/ReferenceConfigTest.java   | 36 ++++++++------
 .../bootstrap/DubboBootstrapMultiInstanceTest.java | 16 +++++--
 .../src/test/resources/dubbo.properties            |  1 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../dubbo-qos}/src/test/resources/dubbo.properties |  1 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../src/test/resources/dubbo.properties            |  1 +
 .../org/apache/dubbo/remoting/api/Connection.java  | 52 +++++++++++++++-----
 .../dubbo/remoting/api/PortUnificationServer.java  | 15 ++++--
 .../src/test/resources/dubbo.properties            |  1 +
 .../src/test/resources/log4j.xml                   |  8 +++-
 .../remoting/transport/netty4/NettyServer.java     | 31 +++++++-----
 .../src/test/resources/dubbo.properties            |  1 +
 .../java/org/apache/dubbo/rpc/ProtocolServer.java  |  4 ++
 .../dubbo/rpc/protocol/AbstractProtocol.java       | 14 ++++++
 .../dubbo/rpc/protocol/AbstractProxyProtocol.java  |  8 ++++
 .../src/test/resources/dubbo.properties            |  1 +
 .../dubbo/rpc/protocol/dubbo/DubboProtocol.java    | 15 ++++--
 .../rpc/protocol/dubbo/DubboProtocolServer.java    |  9 ++++
 .../dubbo/ReferenceCountExchangeClient.java        | 10 ++++
 .../src/test/resources/dubbo.properties            |  1 +
 .../rpc/protocol/rest/BaseRestProtocolServer.java  | 11 ++++-
 dubbo-spring-boot/pom.xml                          | 55 +---------------------
 31 files changed, 201 insertions(+), 106 deletions(-)

diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index a3ba20e..c6046c0 100755
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -1 +1 @@
-distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip
+distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-cluster/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-cluster/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-cluster/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
index 1f56b78..037593e 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
@@ -98,6 +98,11 @@ public class ConfigurationUtils {
     }
 
     // FIXME
+
+    /**
+     * Server shutdown wait timeout mills
+     * @return
+     */
     @SuppressWarnings("deprecation")
     public static int getServerShutdownTimeout(ScopeModel scopeModel) {
         int timeout = DEFAULT_SERVER_SHUTDOWN_TIMEOUT;
diff --git a/dubbo-common/src/test/resources/dubbo.properties b/dubbo-common/src/test/resources/dubbo.properties
index 7598160..4cfa6b8 100644
--- a/dubbo-common/src/test/resources/dubbo.properties
+++ b/dubbo-common/src/test/resources/dubbo.properties
@@ -16,3 +16,5 @@
 #
 
 dubbo=properties
+dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-compatible/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-compatible/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-compatible/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
index 2580cf3..09c07dd 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -51,8 +51,10 @@ import org.apache.dubbo.rpc.model.ModuleModel;
 import org.apache.dubbo.rpc.model.ServiceMetadata;
 import org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker;
 import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -119,25 +121,28 @@ import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
 import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
 
 public class ReferenceConfigTest {
-    private String zkUrl1;
-    private String zkUrl2;
-    private String registryUrl1;
-    private RegistryCenter registryCenter1;
-    private RegistryCenter registryCenter2;
-
-    @BeforeEach
-    public void setUp() throws Exception {
-        DubboBootstrap.reset();
+    private static String zkUrl1;
+    private static String zkUrl2;
+    private static String registryUrl1;
+    private static RegistryCenter registryCenter1;
+    private static RegistryCenter registryCenter2;
+
+    @BeforeAll
+    public static void beforeAll() {
         int zkServerPort1 = NetUtils.getAvailablePort(NetUtils.getRandomPort());
         registryCenter1 = new ZookeeperSingleRegistryCenter(zkServerPort1);
         registryCenter1.startup();
         int zkServerPort2 = NetUtils.getAvailablePort(NetUtils.getRandomPort());
         registryCenter2 = new ZookeeperSingleRegistryCenter(zkServerPort2);
         registryCenter2.startup();
-        this.zkUrl1 = "zookeeper://localhost:" + zkServerPort1;
-        this.zkUrl2 = "zookeeper://localhost:" + zkServerPort2;
-        this.registryUrl1 = "registry://localhost:" + zkServerPort1 + "?registry=zookeeper";
+        zkUrl1 = "zookeeper://localhost:" + zkServerPort1;
+        zkUrl2 = "zookeeper://localhost:" + zkServerPort2;
+        registryUrl1 = "registry://localhost:" + zkServerPort1 + "?registry=zookeeper";
+    }
 
+    @BeforeEach
+    public void setUp() throws Exception {
+        DubboBootstrap.reset();
         ApplicationModel.defaultModel().getApplicationConfigManager();
         DubboBootstrap.getInstance();
     }
@@ -145,10 +150,13 @@ public class ReferenceConfigTest {
     @AfterEach
     public void tearDown() throws IOException {
         DubboBootstrap.reset();
-        registryCenter1.shutdown();
-        registryCenter2.shutdown();
         Mockito.framework().clearInlineMocks();
+    }
 
+    @AfterAll
+    public static void afterAll() {
+        registryCenter1.shutdown();
+        registryCenter2.shutdown();
     }
 
     /**
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java
index a89b459..12b2796 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java
@@ -34,8 +34,10 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 import org.apache.dubbo.rpc.model.FrameworkServiceRepository;
 import org.apache.dubbo.rpc.model.ModuleModel;
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -49,8 +51,8 @@ public class DubboBootstrapMultiInstanceTest {
 
     private static RegistryConfig registryConfig;
 
-    @BeforeEach
-    public void setup() {
+    @BeforeAll
+    public static void beforeAll() {
         registryCenter = new ZookeeperSingleRegistryCenter(NetUtils.getAvailablePort());
         registryCenter.startup();
         RegistryCenter.Instance instance = registryCenter.getRegistryCenterInstance().get(0);
@@ -58,6 +60,15 @@ public class DubboBootstrapMultiInstanceTest {
             instance.getType(),
             instance.getHostname(),
             instance.getPort()));
+    }
+
+    @AfterAll
+    public static void afterAll() {
+        registryCenter.shutdown();
+    }
+
+    @BeforeEach
+    public void setup() {
 
     }
 
@@ -65,7 +76,6 @@ public class DubboBootstrapMultiInstanceTest {
     public void afterEach() {
         SysProps.clear();
         DubboBootstrap.reset();
-        registryCenter.shutdown();
     }
 
     @Test
diff --git a/dubbo-config/dubbo-config-api/src/test/resources/dubbo.properties b/dubbo-config/dubbo-config-api/src/test/resources/dubbo.properties
index 8eaea0d..6a0ada2 100644
--- a/dubbo-config/dubbo-config-api/src/test/resources/dubbo.properties
+++ b/dubbo-config/dubbo-config-api/src/test/resources/dubbo.properties
@@ -1,3 +1,4 @@
 dubbo.override.key2=properties
 dubbo.override.protocol=properties
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-filter/dubbo-filter-cache/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-filter/dubbo-filter-cache/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-filter/dubbo-filter-cache/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-metadata/dubbo-metadata-processor/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-metadata/dubbo-metadata-processor/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-metadata/dubbo-metadata-processor/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-monitor/dubbo-monitor-default/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-monitor/dubbo-monitor-default/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-monitor/dubbo-monitor-default/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-plugin/dubbo-qos/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-plugin/dubbo-qos/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-plugin/dubbo-qos/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-registry/dubbo-registry-api/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-registry/dubbo-registry-api/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-registry/dubbo-registry-api/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-registry/dubbo-registry-dns/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-registry/dubbo-registry-dns/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-registry/dubbo-registry-dns/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/Connection.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/Connection.java
index db6c782..18c9e6d 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/Connection.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/Connection.java
@@ -126,12 +126,22 @@ public class Connection extends AbstractReferenceCounted implements ReferenceCou
             }
             return null;
         }
-        this.connectingPromise = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
+        createConnectingPromise();
         final ChannelFuture promise = bootstrap.connect();
         promise.addListener(this.connectionListener);
         return promise;
     }
 
+    private void createConnectingPromise() {
+        if (this.connectingPromise == null) {
+            synchronized (this) {
+                if (this.connectingPromise == null) {
+                    this.connectingPromise = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
+                }
+            }
+        }
+    }
+
     public Channel getChannel() {
         return channel.get();
     }
@@ -151,9 +161,18 @@ public class Connection extends AbstractReferenceCounted implements ReferenceCou
     }
 
     public void onConnected(Channel channel) {
+        if (isClosed()) {
+            channel.close();
+            if (logger.isDebugEnabled()) {
+                logger.debug(String.format("%s is closed, ignoring connected event", this));
+            }
+            return;
+        }
         this.channel.set(channel);
         // This indicates that the connection is available.
-        this.connectingPromise.setSuccess(CONNECTED_OBJECT);
+        if (this.connectingPromise != null) {
+            this.connectingPromise.setSuccess(CONNECTED_OBJECT);
+        }
         channel.attr(CONNECTION).set(this);
         if (logger.isDebugEnabled()) {
             logger.debug(String.format("%s connected ", this));
@@ -173,7 +192,14 @@ public class Connection extends AbstractReferenceCounted implements ReferenceCou
                 connect();
             }
         }
+
+        this.createConnectingPromise();
         this.connectingPromise.awaitUninterruptibly(this.connectTimeout, TimeUnit.MILLISECONDS);
+        // destroy connectingPromise after used
+        synchronized (this) {
+            this.connectingPromise = null;
+        }
+
         channel = getChannel();
         return channel != null && channel.isActive();
     }
@@ -197,21 +223,21 @@ public class Connection extends AbstractReferenceCounted implements ReferenceCou
 
     @Override
     protected void deallocate() {
-        if (closed.compareAndSet(false, true)) {
-            close();
-        }
-        closePromise.setSuccess(null);
+        close();
     }
 
     public void close() {
-        if (logger.isDebugEnabled()) {
-            logger.debug(String.format("Connection:%s freed ", this));
-        }
-        final Channel current = this.channel.get();
-        if (current != null) {
-            current.close();
+        if (closed.compareAndSet(false, true)) {
+            if (logger.isDebugEnabled()) {
+                logger.debug(String.format("Connection:%s freed ", this));
+            }
+            final Channel current = this.channel.get();
+            if (current != null) {
+                current.close();
+            }
+            this.channel.set(null);
+            closePromise.setSuccess(null);
         }
-        this.channel.set(null);
     }
 
     @Override
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/PortUnificationServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/PortUnificationServer.java
index 32a16e6..d5f1ed1 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/PortUnificationServer.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/PortUnificationServer.java
@@ -28,7 +28,9 @@ import io.netty.channel.group.ChannelGroupFuture;
 import io.netty.channel.group.DefaultChannelGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.concurrent.Future;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -54,6 +56,7 @@ public class PortUnificationServer {
     private static final Logger logger = LoggerFactory.getLogger(PortUnificationServer.class);
     private final List<WireProtocol> protocols;
     private final URL url;
+    private final int serverShutdownTimeoutMills;
     /**
      * netty server bootstrap.
      */
@@ -71,6 +74,8 @@ public class PortUnificationServer {
         // the handler will be wrapped: MultiMessageHandler->HeartbeatHandler->handler
         this.url = ExecutorUtil.setThreadName(url, "DubboPUServerHandler");
         this.protocols = ExtensionLoader.getExtensionLoader(WireProtocol.class).getActivateExtension(url, new String[0]);
+        // read config before destroy
+        serverShutdownTimeoutMills = ConfigurationUtils.getServerShutdownTimeout(getUrl().getOrDefaultModuleModel());
     }
 
     public URL getUrl() {
@@ -149,7 +154,7 @@ public class PortUnificationServer {
 
             if (channelGroup != null) {
                 ChannelGroupFuture closeFuture = channelGroup.close();
-                closeFuture.await(15000);
+                closeFuture.await(serverShutdownTimeoutMills);
             }
             final long cost = System.currentTimeMillis() - st;
             logger.info("Port unification server closed. cost:" + cost);
@@ -163,8 +168,12 @@ public class PortUnificationServer {
 
         try {
             if (bootstrap != null) {
-                bossGroup.shutdownGracefully().syncUninterruptibly();
-                workerGroup.shutdownGracefully().syncUninterruptibly();
+                long timeout = serverShutdownTimeoutMills;
+                long quietPeriod = Math.min(2000L, timeout);
+                Future<?> bossGroupShutdownFuture = bossGroup.shutdownGracefully(quietPeriod, timeout, MILLISECONDS);
+                Future<?> workerGroupShutdownFuture = workerGroup.shutdownGracefully(quietPeriod, timeout, MILLISECONDS);
+                bossGroupShutdownFuture.syncUninterruptibly();
+                workerGroupShutdownFuture.syncUninterruptibly();
             }
         } catch (Throwable e) {
             logger.warn(e.getMessage(), e);
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-remoting/dubbo-remoting-api/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-remoting/dubbo-remoting-api/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/resources/log4j.xml b/dubbo-remoting/dubbo-remoting-api/src/test/resources/log4j.xml
index 16da2d9..786c273 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/test/resources/log4j.xml
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/resources/log4j.xml
@@ -26,4 +26,10 @@
         <level value="WARN"/>
         <appender-ref ref="CONSOLE"/>
     </root>
-</log4j:configuration>
\ No newline at end of file
+
+<!--    <logger name="org.apache.dubbo.remoting" additivity="false">-->
+<!--        <priority value ="debug"/>-->
+<!--        <appender-ref ref="CONSOLE"/>-->
+<!--    </logger>-->
+
+</log4j:configuration>
diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java
index 506e896..262e71c 100644
--- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java
+++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java
@@ -16,7 +16,17 @@
  */
 package org.apache.dubbo.remoting.transport.netty4;
 
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.concurrent.Future;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ExecutorUtil;
@@ -31,15 +41,6 @@ import org.apache.dubbo.remoting.transport.AbstractServer;
 import org.apache.dubbo.remoting.transport.dispatcher.ChannelHandlers;
 import org.apache.dubbo.remoting.utils.UrlUtils;
 
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.buffer.PooledByteBufAllocator;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.timeout.IdleStateHandler;
-
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -73,11 +74,15 @@ public class NettyServer extends AbstractServer implements RemotingServer {
 
     private EventLoopGroup bossGroup;
     private EventLoopGroup workerGroup;
+    private final int serverShutdownTimeoutMills;
 
     public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
         // you can customize name and type of client thread pool by THREAD_NAME_KEY and THREADPOOL_KEY in CommonConstants.
         // the handler will be wrapped: MultiMessageHandler->HeartbeatHandler->handler
         super(ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME), ChannelHandlers.wrap(handler, url));
+
+        // read config before destroy
+        serverShutdownTimeoutMills = ConfigurationUtils.getServerShutdownTimeout(getUrl().getOrDefaultModuleModel());
     }
 
     /**
@@ -154,8 +159,12 @@ public class NettyServer extends AbstractServer implements RemotingServer {
         }
         try {
             if (bootstrap != null) {
-                bossGroup.shutdownGracefully().syncUninterruptibly();
-                workerGroup.shutdownGracefully().syncUninterruptibly();
+                long timeout = serverShutdownTimeoutMills;
+                long quietPeriod = Math.min(2000L, timeout);
+                Future<?> bossGroupShutdownFuture = bossGroup.shutdownGracefully(quietPeriod, timeout, MILLISECONDS);
+                Future<?> workerGroupShutdownFuture = workerGroup.shutdownGracefully(quietPeriod, timeout, MILLISECONDS);
+                bossGroupShutdownFuture.syncUninterruptibly();
+                workerGroupShutdownFuture.syncUninterruptibly();
             }
         } catch (Throwable e) {
             logger.warn(e.getMessage(), e);
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-remoting/dubbo-remoting-zookeeper/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ProtocolServer.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ProtocolServer.java
index 02b8d49..0814111 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ProtocolServer.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ProtocolServer.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.rpc;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.remoting.RemotingServer;
 
+import java.util.Map;
+
 /**
  * Distinct from {@link RemotingServer}, each protocol holds one or more ProtocolServers(the number usually decides by port numbers),
  * while each ProtocolServer holds zero or one RemotingServer.
@@ -44,4 +46,6 @@ public interface ProtocolServer {
     }
 
     void close();
+
+    Map<String, Object> getAttributes();
 }
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java
index 7de1467..4192ba7 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.rpc.protocol;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ConcurrentHashSet;
@@ -38,6 +39,9 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+
 /**
  * abstract ProtocolSupport.
  */
@@ -76,6 +80,16 @@ public abstract class AbstractProtocol implements Protocol, ScopeModelAware {
         return Collections.unmodifiableList(new ArrayList<>(serverMap.values()));
     }
 
+    protected void loadServerProperties(ProtocolServer server) {
+        // read and hold config before destroy
+        int serverShutdownTimeout = ConfigurationUtils.getServerShutdownTimeout(server.getUrl().getScopeModel());
+        server.getAttributes().put(SHUTDOWN_WAIT_KEY, serverShutdownTimeout);
+    }
+
+    protected int getServerShutdownTimeout(ProtocolServer server) {
+        return (int) server.getAttributes().getOrDefault(SHUTDOWN_WAIT_KEY, DEFAULT_SERVER_SHUTDOWN_TIMEOUT);
+    }
+
     @Override
     public void destroy() {
         for (Invoker<?> invoker : invokers) {
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java
index fc22913..bc5415f 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java
@@ -37,7 +37,9 @@ import org.apache.dubbo.rpc.RpcException;
 import java.net.InetSocketAddress;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
@@ -168,6 +170,7 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
 
         private RemotingServer server;
         private String address;
+        private Map<String, Object> attributes = new ConcurrentHashMap<>();
 
         public ProxyProtocolServer(RemotingServer server) {
             this.server = server;
@@ -197,6 +200,11 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
         public void close() {
             server.close();
         }
+
+        @Override
+        public Map<String, Object> getAttributes() {
+            return attributes;
+        }
     }
 
     protected abstract class RemotingServerAdapter implements RemotingServer {
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-rpc/dubbo-rpc-api/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-rpc/dubbo-rpc-api/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-rpc/dubbo-rpc-api/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
index 4361a7a..2555aab 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
@@ -365,7 +365,9 @@ public class DubboProtocol extends AbstractProtocol {
             }
         }
 
-        return new DubboProtocolServer(server);
+        DubboProtocolServer protocolServer = new DubboProtocolServer(server);
+        loadServerProperties(protocolServer);
+        return protocolServer;
     }
 
     private void optimizeSerialization(URL url) throws RpcException {
@@ -593,8 +595,11 @@ public class DubboProtocol extends AbstractProtocol {
      */
     private ReferenceCountExchangeClient buildReferenceCountExchangeClient(URL url) {
         ExchangeClient exchangeClient = initClient(url);
-
-        return new ReferenceCountExchangeClient(exchangeClient);
+        ReferenceCountExchangeClient client = new ReferenceCountExchangeClient(exchangeClient);
+        // read configs
+        int shutdownTimeout = ConfigurationUtils.getServerShutdownTimeout(url.getScopeModel());
+        client.setShutdownWaitTime(shutdownTimeout);
+        return client;
     }
 
     /**
@@ -653,7 +658,7 @@ public class DubboProtocol extends AbstractProtocol {
                     logger.info("Closing dubbo server: " + server.getLocalAddress());
                 }
 
-                server.close(ConfigurationUtils.getServerShutdownTimeout(server.getUrl().getScopeModel()));
+                server.close(getServerShutdownTimeout(protocolServer));
 
             } catch (Throwable t) {
                 logger.warn("Close dubbo server [" + server.getLocalAddress()+ "] failed: " + t.getMessage(), t);
@@ -693,7 +698,7 @@ public class DubboProtocol extends AbstractProtocol {
                 logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress());
             }
 
-            client.close(ConfigurationUtils.getServerShutdownTimeout(client.getUrl().getScopeModel()));
+            client.close(client.getShutdownWaitTime());
 
             // TODO
             /*
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolServer.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolServer.java
index 29abfa0..2cbe12a 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolServer.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolServer.java
@@ -21,10 +21,14 @@ import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.remoting.RemotingServer;
 import org.apache.dubbo.rpc.ProtocolServer;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 public class DubboProtocolServer implements ProtocolServer {
 
     private RemotingServer server;
     private String address;
+    private Map<String, Object> attributes = new ConcurrentHashMap<>();
 
     public DubboProtocolServer(RemotingServer server) {
         this.server = server;
@@ -59,4 +63,9 @@ public class DubboProtocolServer implements ProtocolServer {
     public void close() {
         server.close();
     }
+
+    @Override
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
 }
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/ReferenceCountExchangeClient.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/ReferenceCountExchangeClient.java
index ac222de..d97b933 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/ReferenceCountExchangeClient.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/ReferenceCountExchangeClient.java
@@ -31,6 +31,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;
 import static org.apache.dubbo.remoting.Constants.SEND_RECONNECT_KEY;
 import static org.apache.dubbo.rpc.protocol.dubbo.Constants.LAZY_CONNECT_INITIAL_STATE_KEY;
 
@@ -46,6 +47,7 @@ final class ReferenceCountExchangeClient implements ExchangeClient {
     private final AtomicInteger disconnectCount = new AtomicInteger(0);
     private final Integer warningPeriod = 50;
     private ExchangeClient client;
+    private int shutdownWaitTime = DEFAULT_SERVER_SHUTDOWN_TIMEOUT;
 
     public ReferenceCountExchangeClient(ExchangeClient client) {
         this.client = client;
@@ -230,5 +232,13 @@ final class ReferenceCountExchangeClient implements ExchangeClient {
     public int getCount(){
         return referenceCount.get();
     }
+
+    public int getShutdownWaitTime() {
+        return shutdownWaitTime;
+    }
+
+    public void setShutdownWaitTime(int shutdownWaitTime) {
+        this.shutdownWaitTime = shutdownWaitTime;
+    }
 }
 
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties b/dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/dubbo.properties
similarity index 56%
copy from dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
copy to dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/dubbo.properties
index 9a20f23..1aade88 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/dubbo.properties
@@ -1 +1,2 @@
 dubbo.application.enable-file-cache=false
+dubbo.service.shutdown.wait=200
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/BaseRestProtocolServer.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/BaseRestProtocolServer.java
index 3621848..fcb3a82 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/BaseRestProtocolServer.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/BaseRestProtocolServer.java
@@ -18,9 +18,11 @@ package org.apache.dubbo.rpc.protocol.rest;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.StringUtils;
-
 import org.jboss.resteasy.spi.ResteasyDeployment;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
 import static org.apache.dubbo.rpc.protocol.rest.Constants.EXTENSION_KEY;
 
@@ -28,6 +30,8 @@ public abstract class BaseRestProtocolServer implements RestProtocolServer {
 
     private String address;
 
+    private Map<String, Object> attributes = new ConcurrentHashMap<>();
+
     @Override
     public void start(URL url) {
         getDeployment().getMediaTypeMappings().put("json", "application/json");
@@ -66,6 +70,11 @@ public abstract class BaseRestProtocolServer implements RestProtocolServer {
         this.address = address;
     }
 
+    @Override
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
+
     protected void loadProviders(String value) {
         for (String clazz : COMMA_SPLIT_PATTERN.split(value)) {
             if (!StringUtils.isEmpty(clazz)) {
diff --git a/dubbo-spring-boot/pom.xml b/dubbo-spring-boot/pom.xml
index cbe4a5f..f3ea332 100644
--- a/dubbo-spring-boot/pom.xml
+++ b/dubbo-spring-boot/pom.xml
@@ -79,61 +79,8 @@
         </dependency>
 
     </dependencies>
-    <repositories>
-        <repository>
-            <id>spring-milestone</id>
-            <name>Spring Milestone</name>
-            <url>https://repo.spring.io/milestone</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </repository>
-        <repository>
-            <id>spring-snapshot</id>
-            <name>Spring Snapshot</name>
-            <url>https://repo.spring.io/snapshot</url>
-            <snapshots>
-                <enabled>true</enabled>
-            </snapshots>
-        </repository>
-        <repository>
-            <id>rabbit-milestone</id>
-            <name>Rabbit Milestone</name>
-            <url>https://dl.bintray.com/rabbitmq/maven-milestones</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </repository>
-    </repositories>
-
-    <pluginRepositories>
-        <pluginRepository>
-            <id>central</id>
-            <url>https://repo.maven.apache.org/maven2</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </pluginRepository>
-        <pluginRepository>
-            <id>spring-milestone</id>
-            <name>Spring Milestone</name>
-            <url>https://repo.spring.io/milestone</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </pluginRepository>
-        <pluginRepository>
-            <id>spring-snapshot</id>
-            <name>Spring Snapshot</name>
-            <url>https://repo.spring.io/snapshot</url>
-            <snapshots>
-                <enabled>true</enabled>
-            </snapshots>
-        </pluginRepository>
-    </pluginRepositories>
 
     <profiles>
-
         <profile>
             <!-- Spring Boot 2.0 -->
             <id>spring-boot-2.0</id>
@@ -213,4 +160,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>