From 9407cf4ad07e17decbbffbe756621e5e598b823c Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Sat, 28 Apr 2018 09:42:27 +0800 Subject: [PATCH 1/8] Add a construtor to accept address and protocol for RegistryConfig. --- .../main/java/com/alibaba/dubbo/config/RegistryConfig.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java index 7e2672b9c30..ee13c08873f 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java @@ -96,6 +96,11 @@ public RegistryConfig(String address) { setAddress(address); } + public RegistryConfig(String address, String protocol) { + setAddress(address); + setProtocol(protocol); + } + public static void destroyAll() { AbstractRegistryFactory.destroyAll(); } From e70aaadcecd8a4120c91d93d0599656cb857a087 Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Sat, 28 Apr 2018 11:12:57 +0800 Subject: [PATCH 2/8] Remove unused code. --- .../java/com/alibaba/dubbo/config/RegistryConfig.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java index ee13c08873f..ed9db809d75 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java @@ -101,15 +101,6 @@ public RegistryConfig(String address, String protocol) { setProtocol(protocol); } - public static void destroyAll() { - AbstractRegistryFactory.destroyAll(); - } - - @Deprecated - public static void closeAll() { - destroyAll(); - } - public String getProtocol() { return protocol; } From 8aa45dd6a71fadfa465693ff902ad99d832fce47 Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Mon, 7 May 2018 15:56:47 +0800 Subject: [PATCH 3/8] Ensure Dubbo can shutdown correctly when running both under tomcat and programmably. --- all/pom.xml | 8 ++ dubbo-bootstrap/pom.xml | 47 +++++++ .../dubbo/bootstrap/DubboBootstrap.java | 133 ++++++++++++++++++ .../alibaba/dubbo/config/AbstractConfig.java | 12 -- .../alibaba/dubbo/config/ProtocolConfig.java | 25 ---- .../alibaba/dubbo/config/RegistryConfig.java | 1 - dubbo-config/dubbo-config-spring/pom.xml | 10 ++ .../initializer/DubboApplicationListener.java | 45 ++++++ .../DubboWebApplicationInitializer.java | 33 +++++ .../registry/support/FailbackRegistry.java | 34 ++++- .../dubbo/registry/dubbo/DubboRegistry.java | 12 +- .../registry/multicast/MulticastRegistry.java | 1 + .../dubbo/registry/redis/RedisRegistry.java | 1 + pom.xml | 1 + 14 files changed, 321 insertions(+), 42 deletions(-) create mode 100644 dubbo-bootstrap/pom.xml create mode 100644 dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListener.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java diff --git a/all/pom.xml b/all/pom.xml index 09bfe85daf8..edc0c4ad7a1 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -319,6 +319,13 @@ compile true + + com.alibaba + dubbo-bootstrap + ${project.version} + compile + true + com.alibaba hessian-lite @@ -418,6 +425,7 @@ com.alibaba:dubbo-serialization-fst com.alibaba:dubbo-serialization-kryo com.alibaba:dubbo-serialization-jdk + com.alibaba:dubbo-bootstrap diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml new file mode 100644 index 00000000000..e4320f0ffca --- /dev/null +++ b/dubbo-bootstrap/pom.xml @@ -0,0 +1,47 @@ + + + + dubbo-parent + com.alibaba + 2.6.3-SNAPSHOT + + 4.0.0 + + dubbo-bootstrap + + + + + com.alibaba + dubbo-config-api + ${project.parent.version} + + + com.alibaba + dubbo-common + ${project.parent.version} + + + com.alibaba + dubbo-registry-api + ${project.parent.version} + + + \ No newline at end of file diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java new file mode 100644 index 00000000000..8694e48de35 --- /dev/null +++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.bootstrap; + +import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.ServiceConfig; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; +import com.alibaba.dubbo.rpc.Protocol; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A bootstrap class to easily start and stop Dubbo via programmatic API. + * The bootstrap class will be responsible to cleanup the resources during stop. + */ +public class DubboBootstrap { + + private static final Logger logger = LoggerFactory.getLogger(DubboBootstrap.class); + + /** + * The list of ServiceConfig + */ + private List serviceConfigList; + + /** + * Has it already been destroyed or not? + */ + private final AtomicBoolean destroyed; + + /** + * The shutdown hook used when Dubbo is running under embedded environment + */ + private Thread shutdownHook; + + public DubboBootstrap() { + this.serviceConfigList = new ArrayList(); + this.destroyed = new AtomicBoolean(false); + this.shutdownHook = new Thread(new Runnable() { + @Override + public void run() { + if (logger.isInfoEnabled()) { + logger.info("Run shutdown hook now."); + } + destroy(); + } + }, "DubboShutdownHook"); + } + + /** + * Register service config to bootstrap, which will be called during {@link DubboBootstrap#stop()} + * @param serviceConfig the service + * @return the bootstrap instance + */ + public DubboBootstrap regsiterServiceConfig(ServiceConfig serviceConfig) { + serviceConfigList.add(serviceConfig); + return this; + } + + public void start() { + registerShutdownHook(); + for (ServiceConfig serviceConfig: serviceConfigList) { + serviceConfig.export(); + } + } + + public void stop() { + for (ServiceConfig serviceConfig: serviceConfigList) { + serviceConfig.unexport(); + } + destroy(); + removeShutdownHook(); + } + + /** + * Register the shutdown hook + */ + public void registerShutdownHook() { + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + /** + * Remove this shutdown hook + */ + public void removeShutdownHook() { + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } + catch (IllegalStateException ex) { + // ignore - VM is already shutting down + } + } + + /** + * Destroy all the resources, including registries and protocols. + */ + private void destroy() { + if (!destroyed.compareAndSet(false, true)) { + return; + } + // destroy all the registries + AbstractRegistryFactory.destroyAll(); + // destroy all the protocols + ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Protocol.class); + for (String protocolName : loader.getLoadedExtensions()) { + try { + Protocol protocol = loader.getLoadedExtension(protocolName); + if (protocol != null) { + protocol.destroy(); + } + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java index 73fc07da473..8d8d1828832 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java @@ -73,18 +73,6 @@ public abstract class AbstractConfig implements Serializable { legacyProperties.put("dubbo.service.url", "dubbo.service.address"); } - static { - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - if (logger.isInfoEnabled()) { - logger.info("Run shutdown hook now."); - } - ProtocolConfig.destroyAll(); - } - }, "DubboShutdownHook")); - } - protected String id; private static String convertLegacyValue(String key, String value) { diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java index 0e7a52431c5..b15129bf6fb 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java @@ -21,7 +21,6 @@ import com.alibaba.dubbo.common.status.StatusChecker; import com.alibaba.dubbo.common.threadpool.ThreadPool; import com.alibaba.dubbo.config.support.Parameter; -import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; import com.alibaba.dubbo.remoting.Codec; import com.alibaba.dubbo.remoting.Dispatcher; import com.alibaba.dubbo.remoting.Transporter; @@ -30,7 +29,6 @@ import com.alibaba.dubbo.rpc.Protocol; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; /** * ProtocolConfig @@ -135,8 +133,6 @@ public class ProtocolConfig extends AbstractConfig { // if it's default private Boolean isDefault; - private static final AtomicBoolean destroyed = new AtomicBoolean(false); - public ProtocolConfig() { } @@ -149,27 +145,6 @@ public ProtocolConfig(String name, int port) { setPort(port); } - // TODO: 2017/8/30 to move this method somewhere else - public static void destroyAll() { - if (!destroyed.compareAndSet(false, true)) { - return; - } - - AbstractRegistryFactory.destroyAll(); - - ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Protocol.class); - for (String protocolName : loader.getLoadedExtensions()) { - try { - Protocol protocol = loader.getLoadedExtension(protocolName); - if (protocol != null) { - protocol.destroy(); - } - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } - } - @Parameter(excluded = true) public String getName() { return name; diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java index ed9db809d75..e5684f38be0 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java @@ -18,7 +18,6 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.config.support.Parameter; -import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; import java.util.Map; diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index c7a666080b3..1ba2068346a 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -35,6 +35,11 @@ dubbo-config-api ${project.parent.version} + + com.alibaba + dubbo-bootstrap + ${project.parent.version} + org.springframework spring-beans @@ -43,6 +48,11 @@ org.springframework spring-context + + javax.servlet + javax.servlet-api + provided + com.alibaba dubbo-registry-default diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListener.java new file mode 100644 index 00000000000..43ee49ded8c --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListener.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.spring.initializer; + +import org.apache.dubbo.bootstrap.DubboBootstrap; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.ContextRefreshedEvent; + +/** + * An application listener that listens the ContextClosedEvent. + * Upon the event, this listener will do the necessary clean up to avoid memory leak. + */ +public class DubboApplicationListener implements ApplicationListener { + + private DubboBootstrap dubboBootstrap; + + public DubboApplicationListener() { + dubboBootstrap = new DubboBootstrap(); + } + + @Override + public void onApplicationEvent(ApplicationEvent applicationEvent) { + if (applicationEvent instanceof ContextRefreshedEvent) { + dubboBootstrap.start(); + } else if (applicationEvent instanceof ContextClosedEvent) { + dubboBootstrap.stop(); + } + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java new file mode 100644 index 00000000000..0956d88f275 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.spring.initializer; + +import org.springframework.web.context.AbstractContextLoaderInitializer; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; + + +public class DubboWebApplicationInitializer extends AbstractContextLoaderInitializer { + + @Override + protected WebApplicationContext createRootApplicationContext() { + // TODO need to verify under spring-boot + XmlWebApplicationContext webApplicationContext = new XmlWebApplicationContext(); + webApplicationContext.addApplicationListener(new DubboApplicationListener()); + return webApplicationContext; + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java index ced0efad38d..010e35fb111 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; @@ -57,9 +58,14 @@ public abstract class FailbackRegistry extends AbstractRegistry { private final ConcurrentMap>> failedNotified = new ConcurrentHashMap>>(); + /** + * The time in milliseconds the retryExecutor will wait + */ + private final int retryPeriod; + public FailbackRegistry(URL url) { super(url); - int retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD); + this.retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD); this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { @@ -440,6 +446,32 @@ public void destroy() { } catch (Throwable t) { logger.warn(t.getMessage(), t); } + shutdownExecutorService(retryExecutor, retryPeriod); + } + + /** + * Use the shutdown pattern from: + * https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html + * @param pool the ExecutorService to be shutdown + * @param timeoutInMillis the timeout before terminication + */ + protected void shutdownExecutorService(ExecutorService pool, int timeoutInMillis) { + // Disable new tasks from being submitted + pool.shutdown(); + try { + // Wait a while for existing tasks to terminate + if (!pool.awaitTermination(timeoutInMillis, TimeUnit.MILLISECONDS)) { + pool.shutdownNow(); // Cancel currently executing tasks + // Wait a while for tasks to respond to being cancelled + if (!pool.awaitTermination(timeoutInMillis, TimeUnit.MILLISECONDS)) + logger.warn("ExecutorService did not terminate: " + pool.toString()); + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + pool.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } } // ==== Template method ==== diff --git a/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java b/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java index 9d5ab70159b..8f6c0c841f2 100644 --- a/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java +++ b/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java @@ -47,7 +47,7 @@ public class DubboRegistry extends FailbackRegistry { private static final int RECONNECT_PERIOD_DEFAULT = 3 * 1000; // Scheduled executor service - private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryReconnectTimer", true)); + private final ScheduledExecutorService reconnectTimer = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryReconnectTimer", true)); // Reconnection timer, regular check connection is available. If unavailable, unlimited reconnection. private final ScheduledFuture reconnectFuture; @@ -59,13 +59,18 @@ public class DubboRegistry extends FailbackRegistry { private final RegistryService registryService; + /** + * The time in milliseconds the reconnectTimer will wait + */ + private final int reconnectPeriod; + public DubboRegistry(Invoker registryInvoker, RegistryService registryService) { super(registryInvoker.getUrl()); this.registryInvoker = registryInvoker; this.registryService = registryService; // Start reconnection timer - int reconnectPeriod = registryInvoker.getUrl().getParameter(Constants.REGISTRY_RECONNECT_PERIOD_KEY, RECONNECT_PERIOD_DEFAULT); - reconnectFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + this.reconnectPeriod = registryInvoker.getUrl().getParameter(Constants.REGISTRY_RECONNECT_PERIOD_KEY, RECONNECT_PERIOD_DEFAULT); + reconnectFuture = reconnectTimer.scheduleWithFixedDelay(new Runnable() { @Override public void run() { // Check and connect to the registry @@ -127,6 +132,7 @@ public void destroy() { logger.warn("Failed to cancel reconnect timer", t); } registryInvoker.destroy(); + shutdownExecutorService(reconnectTimer, reconnectPeriod); } @Override diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java b/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java index aa499fc1bc2..5f836ff832d 100644 --- a/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java +++ b/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java @@ -314,6 +314,7 @@ public void destroy() { } catch (Throwable t) { logger.warn(t.getMessage(), t); } + shutdownExecutorService(cleanExecutor, cleanPeriod); } protected void registered(URL url) { diff --git a/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java b/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java index ea4b22cba05..0f75cf6fcc5 100644 --- a/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java +++ b/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java @@ -263,6 +263,7 @@ public void destroy() { logger.warn("Failed to destroy the redis registry client. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); } } + shutdownExecutorService(expireExecutor, expirePeriod); } @Override diff --git a/pom.xml b/pom.xml index 856eca68ef7..9af7c4c947a 100644 --- a/pom.xml +++ b/pom.xml @@ -133,6 +133,7 @@ dubbo-demo dubbo-plugin dubbo-serialization + dubbo-bootstrap dependencies-bom bom all From bfa0a43ac903d2bf1a71bfff55892de2e73b516c Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Wed, 9 May 2018 12:03:22 +0800 Subject: [PATCH 4/8] Add comments. --- .../initializer/DubboWebApplicationInitializer.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java index 0956d88f275..8d0f79db14a 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java @@ -20,12 +20,19 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.XmlWebApplicationContext; - +/** + * An initializer to register {@link DubboApplicationListener} + * to the ApplicationContext seamlessly. + */ public class DubboWebApplicationInitializer extends AbstractContextLoaderInitializer { + /** + * This method won't be triggered if running on spring-boot. + * It only works when running under a servlet container. + * @return a WebApplicationContext with DubboApplicationListener registered. + */ @Override protected WebApplicationContext createRootApplicationContext() { - // TODO need to verify under spring-boot XmlWebApplicationContext webApplicationContext = new XmlWebApplicationContext(); webApplicationContext.addApplicationListener(new DubboApplicationListener()); return webApplicationContext; From ff073a1b8868080fc83de91d187362d0a04640fd Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Wed, 9 May 2018 15:46:17 +0800 Subject: [PATCH 5/8] Add dependency. --- dubbo-config/dubbo-config-spring/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index 1ba2068346a..170ac2c1e85 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -44,6 +44,10 @@ org.springframework spring-beans + + org.springframework + spring-web + org.springframework spring-context From 0b83562c152c3c9de520e372684fb9382e7cd053 Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Wed, 9 May 2018 17:16:09 +0800 Subject: [PATCH 6/8] Using ExecutorUtil#gracefulShutdown instead of create a new method. --- .../dubbo/common/utils/ExecutorUtil.java | 10 ++++++- .../registry/support/FailbackRegistry.java | 29 ++----------------- .../dubbo/registry/dubbo/DubboRegistry.java | 3 +- .../registry/multicast/MulticastRegistry.java | 3 +- .../dubbo/registry/redis/RedisRegistry.java | 3 +- 5 files changed, 17 insertions(+), 31 deletions(-) diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java index 6b07cc8035f..d605e130660 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java @@ -43,19 +43,27 @@ public static boolean isTerminated(Executor executor) { return false; } + /** + * Use the shutdown pattern from: + * https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html + * @param executor the Executor to shutdown + * @param timeout the timeout in milliseconds before termination + */ public static void gracefulShutdown(Executor executor, int timeout) { if (!(executor instanceof ExecutorService) || isTerminated(executor)) { return; } final ExecutorService es = (ExecutorService) executor; try { - es.shutdown(); // Disable new tasks from being submitted + // Disable new tasks from being submitted + es.shutdown(); } catch (SecurityException ex2) { return; } catch (NullPointerException ex2) { return; } try { + // Wait a while for existing tasks to terminate if (!es.awaitTermination(timeout, TimeUnit.MILLISECONDS)) { es.shutdownNow(); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java index 010e35fb111..e081957e681 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java @@ -19,6 +19,7 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.common.utils.ExecutorUtil; import com.alibaba.dubbo.common.utils.NamedThreadFactory; import com.alibaba.dubbo.registry.NotifyListener; @@ -29,7 +30,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; @@ -446,32 +446,7 @@ public void destroy() { } catch (Throwable t) { logger.warn(t.getMessage(), t); } - shutdownExecutorService(retryExecutor, retryPeriod); - } - - /** - * Use the shutdown pattern from: - * https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html - * @param pool the ExecutorService to be shutdown - * @param timeoutInMillis the timeout before terminication - */ - protected void shutdownExecutorService(ExecutorService pool, int timeoutInMillis) { - // Disable new tasks from being submitted - pool.shutdown(); - try { - // Wait a while for existing tasks to terminate - if (!pool.awaitTermination(timeoutInMillis, TimeUnit.MILLISECONDS)) { - pool.shutdownNow(); // Cancel currently executing tasks - // Wait a while for tasks to respond to being cancelled - if (!pool.awaitTermination(timeoutInMillis, TimeUnit.MILLISECONDS)) - logger.warn("ExecutorService did not terminate: " + pool.toString()); - } - } catch (InterruptedException ie) { - // (Re-)Cancel if current thread also interrupted - pool.shutdownNow(); - // Preserve interrupt status - Thread.currentThread().interrupt(); - } + ExecutorUtil.gracefulShutdown(retryExecutor, retryPeriod); } // ==== Template method ==== diff --git a/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java b/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java index 8f6c0c841f2..bf8056e6271 100644 --- a/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java +++ b/dubbo-registry/dubbo-registry-default/src/main/java/com/alibaba/dubbo/registry/dubbo/DubboRegistry.java @@ -21,6 +21,7 @@ import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ExecutorUtil; import com.alibaba.dubbo.common.utils.NamedThreadFactory; import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.registry.NotifyListener; @@ -132,7 +133,7 @@ public void destroy() { logger.warn("Failed to cancel reconnect timer", t); } registryInvoker.destroy(); - shutdownExecutorService(reconnectTimer, reconnectPeriod); + ExecutorUtil.gracefulShutdown(reconnectTimer, reconnectPeriod); } @Override diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java b/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java index 5f836ff832d..d3928397b3b 100644 --- a/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java +++ b/dubbo-registry/dubbo-registry-multicast/src/main/java/com/alibaba/dubbo/registry/multicast/MulticastRegistry.java @@ -21,6 +21,7 @@ import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.common.utils.ExecutorUtil; import com.alibaba.dubbo.common.utils.NamedThreadFactory; import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.StringUtils; @@ -314,7 +315,7 @@ public void destroy() { } catch (Throwable t) { logger.warn(t.getMessage(), t); } - shutdownExecutorService(cleanExecutor, cleanPeriod); + ExecutorUtil.gracefulShutdown(cleanExecutor, cleanPeriod); } protected void registered(URL url) { diff --git a/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java b/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java index 0f75cf6fcc5..6a997918abf 100644 --- a/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java +++ b/dubbo-registry/dubbo-registry-redis/src/main/java/com/alibaba/dubbo/registry/redis/RedisRegistry.java @@ -20,6 +20,7 @@ import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ExecutorUtil; import com.alibaba.dubbo.common.utils.NamedThreadFactory; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.common.utils.UrlUtils; @@ -263,7 +264,7 @@ public void destroy() { logger.warn("Failed to destroy the redis registry client. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); } } - shutdownExecutorService(expireExecutor, expirePeriod); + ExecutorUtil.gracefulShutdown(expireExecutor, expirePeriod); } @Override From 390db5508371004f43bae24c02025cb9b61a5acf Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Wed, 9 May 2018 18:25:01 +0800 Subject: [PATCH 7/8] Correct pom version. --- dubbo-bootstrap/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml index e4320f0ffca..bb2b1a4ecd3 100644 --- a/dubbo-bootstrap/pom.xml +++ b/dubbo-bootstrap/pom.xml @@ -20,7 +20,7 @@ dubbo-parent com.alibaba - 2.6.3-SNAPSHOT + 2.6.2-SNAPSHOT 4.0.0 From 30ee49a3eabaf2991a45fe89567b931d02995a36 Mon Sep 17 00:00:00 2001 From: Huxing Zhang Date: Thu, 10 May 2018 16:16:43 +0800 Subject: [PATCH 8/8] Fix UT failure. --- .../com/alibaba/dubbo/config/ProtocolConfigTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/ProtocolConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/ProtocolConfigTest.java index 43f3621e287..fb105dd5d4e 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/ProtocolConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/ProtocolConfigTest.java @@ -17,7 +17,6 @@ package com.alibaba.dubbo.config; -import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.rpc.Protocol; import org.junit.Test; import org.mockito.Mockito; @@ -32,15 +31,6 @@ import static org.junit.Assert.assertThat; public class ProtocolConfigTest { - @Test - public void testDestroyAll() throws Exception { - Protocol protocol = Mockito.mock(Protocol.class); - MockProtocol2.delegate = protocol; - ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Protocol.class); - loader.getExtension("mockprotocol2"); - ProtocolConfig.destroyAll(); - Mockito.verify(protocol).destroy(); - } @Test public void testDestroy() throws Exception {