Merge branch 'ralf0131-graceful-shutdown-in-tomcat'
This commit is contained in:
commit
b48e8bac04
|
|
@ -319,6 +319,13 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-bootstrap</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>hessian-lite</artifactId>
|
||||
|
|
@ -418,6 +425,7 @@
|
|||
<include>com.alibaba:dubbo-serialization-fst</include>
|
||||
<include>com.alibaba:dubbo-serialization-kryo</include>
|
||||
<include>com.alibaba:dubbo-serialization-jdk</include>
|
||||
<include>com.alibaba:dubbo-bootstrap</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>dubbo-parent</artifactId>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<version>2.6.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-bootstrap</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-config-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -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<ServiceConfig> 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<ServiceConfig>();
|
||||
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<Protocol> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,19 +43,27 @@ public class ExecutorUtil {
|
|||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import com.alibaba.dubbo.common.serialize.Serialization;
|
|||
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.remoting.telnet.TelnetHandler;
|
|||
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 class ProtocolConfig extends AbstractConfig {
|
|||
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<Protocol> 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;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package com.alibaba.dubbo.config;
|
|||
|
||||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.config.support.Parameter;
|
||||
import com.alibaba.dubbo.registry.support.AbstractRegistryFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -96,13 +95,9 @@ public class RegistryConfig extends AbstractConfig {
|
|||
setAddress(address);
|
||||
}
|
||||
|
||||
public static void destroyAll() {
|
||||
AbstractRegistryFactory.destroyAll();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void closeAll() {
|
||||
destroyAll();
|
||||
public RegistryConfig(String address, String protocol) {
|
||||
setAddress(address);
|
||||
setProtocol(protocol);
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package com.alibaba.dubbo.config;
|
||||
|
||||
import com.alibaba.dubbo.common.extension.ExtensionLoader;
|
||||
import com.alibaba.dubbo.config.mock.MockProtocol2;
|
||||
import com.alibaba.dubbo.rpc.Protocol;
|
||||
import org.junit.Test;
|
||||
|
|
@ -33,15 +32,6 @@ import static org.hamcrest.Matchers.is;
|
|||
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<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
|
||||
loader.getExtension("mockprotocol2");
|
||||
ProtocolConfig.destroyAll();
|
||||
Mockito.verify(protocol).destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroy() throws Exception {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
<<<<<<< HEAD
|
||||
import com.alibaba.dubbo.common.extension.ExtensionLoader;
|
||||
import com.alibaba.dubbo.config.mock.MockProtocol2;
|
||||
=======
|
||||
>>>>>>> e201004e985f3ae43ee8c65baa16bcc0aecc0000
|
||||
import com.alibaba.dubbo.rpc.Protocol;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class ProtocolConfigTest {
|
||||
|
||||
@Test
|
||||
public void testDestroy() throws Exception {
|
||||
Protocol protocol = Mockito.mock(Protocol.class);
|
||||
MockProtocol2.delegate = protocol;
|
||||
ProtocolConfig protocolConfig = new ProtocolConfig();
|
||||
protocolConfig.setName("mockprotocol2");
|
||||
protocolConfig.destory();
|
||||
Mockito.verify(protocol).destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testName() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setName("name");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
ProtocolConfig.appendParameters(parameters, protocol);
|
||||
assertThat(protocol.getName(), equalTo("name"));
|
||||
assertThat(protocol.getId(), equalTo("name"));
|
||||
assertThat(parameters.isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setHost("host");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
ProtocolConfig.appendParameters(parameters, protocol);
|
||||
assertThat(protocol.getHost(), equalTo("host"));
|
||||
assertThat(parameters.isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPort() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setPort(8080);
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
ProtocolConfig.appendParameters(parameters, protocol);
|
||||
assertThat(protocol.getPort(), equalTo(8080));
|
||||
assertThat(parameters.isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPath() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setContextpath("context-path");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
ProtocolConfig.appendParameters(parameters, protocol);
|
||||
assertThat(protocol.getPath(), equalTo("context-path"));
|
||||
assertThat(protocol.getContextpath(), equalTo("context-path"));
|
||||
assertThat(parameters.isEmpty(), is(true));
|
||||
protocol.setPath("path");
|
||||
assertThat(protocol.getPath(), equalTo("path"));
|
||||
assertThat(protocol.getContextpath(), equalTo("path"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreads() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setThreads(10);
|
||||
assertThat(protocol.getThreads(), is(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIothreads() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setIothreads(10);
|
||||
assertThat(protocol.getIothreads(), is(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueues() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setQueues(10);
|
||||
assertThat(protocol.getQueues(), is(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccepts() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setAccepts(10);
|
||||
assertThat(protocol.getAccepts(), is(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCodec() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setName("dubbo");
|
||||
protocol.setCodec("mockcodec");
|
||||
assertThat(protocol.getCodec(), equalTo("mockcodec"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccesslog() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setAccesslog("access.log");
|
||||
assertThat(protocol.getAccesslog(), equalTo("access.log"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTelnet() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setTelnet("mocktelnethandler");
|
||||
assertThat(protocol.getTelnet(), equalTo("mocktelnethandler"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setRegister(true);
|
||||
assertThat(protocol.isRegister(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransporter() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setTransporter("mocktransporter");
|
||||
assertThat(protocol.getTransporter(), equalTo("mocktransporter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExchanger() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setExchanger("mockexchanger");
|
||||
assertThat(protocol.getExchanger(), equalTo("mockexchanger"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatcher() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setDispatcher("mockdispatcher");
|
||||
assertThat(protocol.getDispatcher(), equalTo("mockdispatcher"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworker() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setNetworker("networker");
|
||||
assertThat(protocol.getNetworker(), equalTo("networker"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameters() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setParameters(Collections.singletonMap("k1", "v1"));
|
||||
assertThat(protocol.getParameters(), hasEntry("k1", "v1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefault() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setDefault(true);
|
||||
assertThat(protocol.isDefault(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeepAlive() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setKeepAlive(true);
|
||||
assertThat(protocol.getKeepAlive(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptimizer() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setOptimizer("optimizer");
|
||||
assertThat(protocol.getOptimizer(), equalTo("optimizer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtension() throws Exception {
|
||||
ProtocolConfig protocol = new ProtocolConfig();
|
||||
protocol.setExtension("extension");
|
||||
assertThat(protocol.getExtension(), equalTo("extension"));
|
||||
}
|
||||
}
|
||||
|
|
@ -35,14 +35,28 @@
|
|||
<artifactId>dubbo-config-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-bootstrap</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-registry-default</artifactId>
|
||||
|
|
|
|||
|
|
@ -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<ApplicationEvent> {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
XmlWebApplicationContext webApplicationContext = new XmlWebApplicationContext();
|
||||
webApplicationContext.addApplicationListener(new DubboApplicationListener());
|
||||
return webApplicationContext;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ package com.alibaba.dubbo.registry.support;
|
|||
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;
|
||||
|
||||
|
|
@ -57,9 +58,14 @@ public abstract class FailbackRegistry extends AbstractRegistry {
|
|||
|
||||
private final ConcurrentMap<URL, Map<NotifyListener, List<URL>>> failedNotified = new ConcurrentHashMap<URL, Map<NotifyListener, List<URL>>>();
|
||||
|
||||
/**
|
||||
* 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,7 @@ public abstract class FailbackRegistry extends AbstractRegistry {
|
|||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
ExecutorUtil.gracefulShutdown(retryExecutor, retryPeriod);
|
||||
}
|
||||
|
||||
// ==== Template method ====
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.alibaba.dubbo.common.URL;
|
|||
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;
|
||||
|
|
@ -47,7 +48,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 +60,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<RegistryService> 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 +133,7 @@ public class DubboRegistry extends FailbackRegistry {
|
|||
logger.warn("Failed to cancel reconnect timer", t);
|
||||
}
|
||||
registryInvoker.destroy();
|
||||
ExecutorUtil.gracefulShutdown(reconnectTimer, reconnectPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,6 +21,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.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,6 +315,7 @@ public class MulticastRegistry extends FailbackRegistry {
|
|||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
ExecutorUtil.gracefulShutdown(cleanExecutor, cleanPeriod);
|
||||
}
|
||||
|
||||
protected void registered(URL url) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.alibaba.dubbo.common.Constants;
|
|||
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,6 +264,7 @@ public class RedisRegistry extends FailbackRegistry {
|
|||
logger.warn("Failed to destroy the redis registry client. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
ExecutorUtil.gracefulShutdown(expireExecutor, expirePeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in New Issue