You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2018/11/05 02:49:15 UTC

[incubator-dubbo] branch master updated: Merge pull request #2725, problems of graceful shutdown in 2.6.3 and some recommendation.

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

liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git


The following commit(s) were added to refs/heads/master by this push:
     new 0d51bc4  Merge pull request #2725, problems of graceful shutdown in 2.6.3 and some recommendation.
0d51bc4 is described below

commit 0d51bc4751583cc31e7b65c5a79e335fa76aae89
Author: Ian Luo <ia...@gmail.com>
AuthorDate: Mon Nov 5 10:49:10 2018 +0800

    Merge pull request #2725, problems of graceful shutdown in 2.6.3 and some recommendation.
---
 dubbo-all/pom.xml                                  |   8 --
 dubbo-bom/pom.xml                                  |   5 -
 dubbo-bootstrap/pom.xml                            |  47 ---------
 .../org/apache/dubbo/bootstrap/DubboBootstrap.java | 111 ---------------------
 .../org/apache/dubbo/config/ProtocolConfig.java    |  11 +-
 dubbo-config/dubbo-config-spring/pom.xml           |   7 +-
 .../apache/dubbo/config/spring/AnnotationBean.java |  23 ++---
 .../apache/dubbo/config/spring/ServiceBean.java    |  26 +----
 .../spring/extension/SpringExtensionFactory.java   |  19 ++++
 .../DubboApplicationContextInitializer.java        |  39 --------
 .../initializer/DubboApplicationListener.java      |  49 ---------
 .../spring/initializer/DubboContextListener.java   |  72 -------------
 .../dubbo/config/spring/util/BeanFactoryUtils.java |  27 +++++
 .../src/main/resources/META-INF/web-fragment.xml   |  22 ----
 .../DubboApplicationContextInitializerTest.java    |  88 ----------------
 .../initializer/DubboApplicationListenerTest.java  |  59 -----------
 dubbo-container/dubbo-container-spring/pom.xml     |   7 +-
 .../dubbo/container/spring/SpringContainer.java    |   6 +-
 dubbo-distribution/pom.xml                         |   5 -
 pom.xml                                            |   1 -
 20 files changed, 65 insertions(+), 567 deletions(-)

diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index 8e8fa66..12d9ec9 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -327,13 +327,6 @@
         </dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-bootstrap</artifactId>
-            <version>${project.version}</version>
-            <scope>compile</scope>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-compatible</artifactId>
             <version>${project.version}</version>
             <scope>compile</scope>
@@ -439,7 +432,6 @@
                                     <include>org.apache.dubbo:dubbo-serialization-kryo</include>
                                     <include>org.apache.dubbo:dubbo-serialization-jdk</include>
                                     <include>org.apache.dubbo:dubbo-serialization-protostuff</include>
-                                    <include>org.apache.dubbo:dubbo-bootstrap</include>
                                 </includes>
                             </artifactSet>
                             <transformers>
diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index 15c8ae8..dac2456 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -285,11 +285,6 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.dubbo</groupId>
-                <artifactId>dubbo-bootstrap</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.dubbo</groupId>
                 <artifactId>dubbo-compatible</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml
deleted file mode 100644
index a082550..0000000
--- a/dubbo-bootstrap/pom.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<!--
-  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>org.apache.dubbo</groupId>
-        <version>2.7.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>dubbo-bootstrap</artifactId>
-
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-config-api</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-common</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-registry-api</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-    </dependencies>
-</project>
\ 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
deleted file mode 100644
index b896c0e..0000000
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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 org.apache.dubbo.config.DubboShutdownHook;
-import org.apache.dubbo.config.ServiceConfig;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 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 {
-
-    /**
-     * The list of ServiceConfig
-     */
-    private List<ServiceConfig> serviceConfigList;
-
-    /**
-     * Whether register the shutdown hook during start?
-     */
-    private final boolean registerShutdownHookOnStart;
-
-    /**
-     * The shutdown hook used when Dubbo is running under embedded environment
-     */
-    private DubboShutdownHook shutdownHook;
-
-    public DubboBootstrap() {
-        this(true, DubboShutdownHook.getDubboShutdownHook());
-    }
-
-    public DubboBootstrap(boolean registerShutdownHookOnStart) {
-        this(registerShutdownHookOnStart, DubboShutdownHook.getDubboShutdownHook());
-    }
-
-    public DubboBootstrap(boolean registerShutdownHookOnStart, DubboShutdownHook shutdownHook) {
-        this.serviceConfigList = new ArrayList<ServiceConfig>();
-        this.shutdownHook = shutdownHook;
-        this.registerShutdownHookOnStart = registerShutdownHookOnStart;
-    }
-
-    /**
-     * Register service config to bootstrap, which will be called during {@link DubboBootstrap#stop()}
-     * @param serviceConfig the service
-     * @return the bootstrap instance
-     */
-    public DubboBootstrap registerServiceConfig(ServiceConfig serviceConfig) {
-        serviceConfigList.add(serviceConfig);
-        return this;
-    }
-
-    public void start() {
-        if (registerShutdownHookOnStart) {
-            registerShutdownHook();
-        } else {
-            // DubboShutdown hook has been registered in AbstractConfig,
-            // we need to remove it explicitly
-            removeShutdownHook();
-        }
-        for (ServiceConfig serviceConfig: serviceConfigList) {
-            serviceConfig.export();
-        }
-    }
-
-    public void stop() {
-        for (ServiceConfig serviceConfig: serviceConfigList) {
-            serviceConfig.unexport();
-        }
-        shutdownHook.destroyAll();
-        if (registerShutdownHookOnStart) {
-            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
-        }
-    }
-}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
index 3ae3329..7582169 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
@@ -470,13 +470,4 @@ public class ProtocolConfig extends AbstractConfig {
             ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).destroy();
         }
     }
-
-    /**
-     * Just for compatibility.
-     * It should be deleted in the next major version, say 2.7.x.
-     */
-    @Deprecated
-    public static void destroyAll() {
-        DubboShutdownHook.getDubboShutdownHook().destroyAll();
-    }
-}
\ No newline at end of file
+}
diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml
index 995209d..626556c 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -35,11 +35,6 @@
             <version>${project.parent.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-bootstrap</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-beans</artifactId>
         </dependency>
@@ -157,4 +152,4 @@
             -->
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java
index 7612c33..6b54a39 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java
@@ -28,7 +28,6 @@ import org.apache.dubbo.config.ModuleConfig;
 import org.apache.dubbo.config.MonitorConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ProviderConfig;
-import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.annotation.Reference;
@@ -111,17 +110,16 @@ public class AnnotationBean extends AbstractConfig implements DisposableBean, Be
 
     @Override
     public void destroy() {
-
-        //  This will only be called for singleton scope bean, and expected to be called by spring shutdown hook when BeanFactory/ApplicationContext destroys.
-        //  We will guarantee dubbo related resources being released with dubbo shutdown hook.
-
-        //  for (ServiceConfig<?> serviceConfig : serviceConfigs) {
-        //      try {
-        //          serviceConfig.unexport();
-        //      } catch (Throwable e) {
-        //          logger.error(e.getMessage(), e);
-        //      }
-        //  }
+        // no need to destroy here
+        // see org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener
+        /*
+          for (ServiceConfig<?> serviceConfig : serviceConfigs) {
+              try {
+                  serviceConfig.unexport();
+              } catch (Throwable e) {
+                  logger.error(e.getMessage(), e);
+              }
+          }
 
         for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {
             try {
@@ -130,6 +128,7 @@ public class AnnotationBean extends AbstractConfig implements DisposableBean, Be
                 logger.error(e.getMessage(), e);
             }
         }
+        */
     }
 
     @Override
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
index 6d7bc9b..19dcef1 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
@@ -34,13 +34,13 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ContextRefreshedEvent;
-import org.springframework.context.support.AbstractApplicationContext;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.addApplicationListener;
+
 /**
  * ServiceFactoryBean
  *
@@ -72,23 +72,7 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
     public void setApplicationContext(ApplicationContext applicationContext) {
         this.applicationContext = applicationContext;
         SpringExtensionFactory.addApplicationContext(applicationContext);
-        try {
-            Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); // backward compatibility to spring 2.0.1
-            method.invoke(applicationContext, this);
-            supportedApplicationListener = true;
-        } catch (Throwable t) {
-            if (applicationContext instanceof AbstractApplicationContext) {
-                try {
-                    Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); // backward compatibility to spring 2.0.1
-                    if (!method.isAccessible()) {
-                        method.setAccessible(true);
-                    }
-                    method.invoke(applicationContext, this);
-                    supportedApplicationListener = true;
-                } catch (Throwable t2) {
-                }
-            }
-        }
+        supportedApplicationListener = addApplicationListener(applicationContext, this);
     }
 
     @Override
@@ -249,9 +233,7 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
 
     @Override
     public void destroy() throws Exception {
-        // This will only be called for singleton scope bean, and expected to be called by spring shutdown hook when BeanFactory/ApplicationContext destroys.
-        // We will guarantee dubbo related resources being released with dubbo shutdown hook.
-        //unexport();
+        // no need to export here, see org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener
     }
 
     // merged from dubbox
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactory.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactory.java
index ea63a35..988bcec 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactory.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactory.java
@@ -21,9 +21,14 @@ import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.config.DubboShutdownHook;
+import org.apache.dubbo.config.spring.util.BeanFactoryUtils;
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
 
 import java.util.Set;
 
@@ -34,9 +39,11 @@ public class SpringExtensionFactory implements ExtensionFactory {
     private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
 
     private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
+    private static final ApplicationListener shutdownHookListener = new ShutdownHookListener();
 
     public static void addApplicationContext(ApplicationContext context) {
         contexts.add(context);
+        BeanFactoryUtils.addApplicationListener(context, shutdownHookListener);
     }
 
     public static void removeApplicationContext(ApplicationContext context) {
@@ -93,4 +100,16 @@ public class SpringExtensionFactory implements ExtensionFactory {
         return null;
     }
 
+    private static class ShutdownHookListener implements ApplicationListener {
+        @Override
+        public void onApplicationEvent(ApplicationEvent event) {
+            if (event instanceof ContextClosedEvent) {
+                // we call it anyway since dubbo shutdown hook make sure its destroyAll() is re-entrant.
+                // pls. note we should not remove dubbo shutdown hook when spring framework is present, this is because
+                // its shutdown hook may not be installed.
+                DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();
+                shutdownHook.destroyAll();
+            }
+        }
+    }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializer.java
deleted file mode 100644
index 36727e6..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.config.spring.initializer;
-
-import org.springframework.context.ApplicationContextInitializer;
-import org.springframework.context.ConfigurableApplicationContext;
-
-/**
- * Automatically register {@link DubboApplicationListener} to Spring context
- * A {@link org.springframework.web.context.ContextLoaderListener} class is defined in
- * src/main/resources/META-INF/web-fragment.xml
- * In the web-fragment.xml, {@link DubboApplicationContextInitializer} is defined in context params.
- * This file will be discovered if running under a servlet 3.0+ container.
- * Even if user specifies {@link org.springframework.web.context.ContextLoaderListener} in web.xml,
- * it will be merged to web.xml.
- * If user specifies <metadata-complete="true" /> in web.xml, this will no take effect,
- * unless user configures {@link DubboApplicationContextInitializer} explicitly in web.xml.
- */
-public class DubboApplicationContextInitializer implements ApplicationContextInitializer {
-
-    @Override
-    public void initialize(ConfigurableApplicationContext applicationContext) {
-        applicationContext.addApplicationListener(new DubboApplicationListener());
-    }
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListener.java
deleted file mode 100644
index 8b6409b..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListener.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.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(false);
-    }
-
-    public DubboApplicationListener(DubboBootstrap dubboBootstrap) {
-        this.dubboBootstrap = 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/org/apache/dubbo/config/spring/initializer/DubboContextListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboContextListener.java
deleted file mode 100644
index 35b2b70..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboContextListener.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.config.spring.initializer;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-/**
- * A Dubbo context listener is a delegation to org.springframework.web.context.ContextLoaderListener. This is necessary,
- * because Dubbo is packaged into all-in-one jar, therefore it contains a web-fragment.xml from this sub module which's
- * used for helping to assemble spring context listener automatically when it's not configured explicitly by user in
- * web.xml. It works fine with spring, but it will lead to ClassNotFound exception and fail tomcat's bootup when user
- * doesn't depend on spring framework.
- */
-public class DubboContextListener implements ServletContextListener {
-    private static final Log logger = LogFactory.getLog(DubboContextListener.class);
-
-    private static final String SPRING_CONTEXT_LISTENER = "org.springframework.web.context.ContextLoaderListener";
-    private static final String SPRING_CONTEXT_ROOT = "org.springframework.web.context.WebApplicationContext.ROOT";
-
-    private ServletContextListener springContextListener;
-    private boolean executed = false;
-
-    public DubboContextListener() {
-        try {
-            Class c = Class.forName(SPRING_CONTEXT_LISTENER);
-            springContextListener = (ServletContextListener) c.newInstance();
-        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
-            logger.warn("Servlet container detects dubbo's web fragment configuration, and tries to load " +
-                    "org.springframework.web.context.ContextLoaderListener but fails to find the class. " +
-                    "If the application don't rely on Spring framework, pls. simply ignore");
-        }
-    }
-
-    @Override
-    public void contextInitialized(ServletContextEvent servletContextEvent) {
-        if (springContextListener != null) {
-            // if spring context listener has already been registered, then do nothing
-            ServletContext context = servletContextEvent.getServletContext();
-            if (context.getAttribute(SPRING_CONTEXT_ROOT) == null) {
-                executed = true;
-                springContextListener.contextInitialized(servletContextEvent);
-            }
-        }
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent servletContextEvent) {
-        if (springContextListener != null && executed) {
-            springContextListener.contextDestroyed(servletContextEvent);
-        }
-    }
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java
index e787399..e9b1708 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java
@@ -20,7 +20,11 @@ import org.apache.dubbo.common.utils.StringUtils;
 import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.ListableBeanFactory;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.support.AbstractApplicationContext;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -89,4 +93,27 @@ public class BeanFactoryUtils {
 
     }
 
+    public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) {
+        try {
+            // backward compatibility to spring 2.0.1
+            Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class);
+            method.invoke(applicationContext, listener);
+            return true;
+        } catch (Throwable t) {
+            if (applicationContext instanceof AbstractApplicationContext) {
+                try {
+                    // backward compatibility to spring 2.0.1
+                    Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class);
+                    if (!method.isAccessible()) {
+                        method.setAccessible(true);
+                    }
+                    method.invoke(applicationContext, listener);
+                    return true;
+                } catch (Throwable t2) {
+                    // ignore
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml
deleted file mode 100644
index e1eef6b..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
-              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">
-
-    <name>dubbo_fragment</name>
-
-    <ordering>
-        <before>
-            <others/>
-        </before>
-    </ordering>
-
-    <context-param>
-        <param-name>contextInitializerClasses</param-name>
-        <param-value>org.apache.dubbo.config.spring.initializer.DubboApplicationContextInitializer</param-value>
-    </context-param>
-
-    <listener>
-        <listener-class>org.apache.dubbo.config.spring.initializer.DubboContextListener</listener-class>
-    </listener>
-
-</web-fragment>
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java
deleted file mode 100644
index 02dda03..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.config.spring.initializer;
-
-import org.apache.catalina.core.StandardContext;
-import org.apache.catalina.startup.ContextConfig;
-import org.apache.catalina.startup.Tomcat;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.web.context.ContextLoaderListener;
-
-
-public class DubboApplicationContextInitializerTest {
-
-    @Test
-    public void testSpringContextLoaderListenerInWebXml() throws Exception {
-        Tomcat tomcat = new Tomcat();
-        tomcat.setBaseDir("target/test-classes");
-        tomcat.setPort(12345);
-        StandardContext context = new StandardContext();
-        context.setName("test");
-        context.setDocBase("test");
-        context.setPath("/test");
-        context.addLifecycleListener(new ContextConfig());
-        tomcat.getHost().addChild(context);
-        tomcat.start();
-        // there should be 2 application listeners, one is spring context listener,
-        // the other is its wrapper dubbo introduces.
-        Assert.assertEquals(2, context.getApplicationLifecycleListeners().length);
-        // the first one should be Spring's built in ContextLoaderListener.
-        Assert.assertTrue(context.getApplicationLifecycleListeners()[0] instanceof ContextLoaderListener);
-        tomcat.stop();
-        tomcat.destroy();
-    }
-
-    @Test
-    public void testNoListenerInWebXml() throws Exception {
-        Tomcat tomcat = new Tomcat();
-        tomcat.setBaseDir("target/test-classes");
-        tomcat.setPort(12345);
-        StandardContext context = new StandardContext();
-        context.setName("test2");
-        context.setDocBase("test2");
-        context.setPath("/test2");
-        context.addLifecycleListener(new ContextConfig());
-        tomcat.getHost().addChild(context);
-        tomcat.start();
-        // there should be 1 application listener, which is spring context listener's wrapper introduced by dubbo
-        Assert.assertEquals(1, context.getApplicationLifecycleListeners().length);
-        // the first one should be Spring's built in ContextLoaderListener.
-        Assert.assertTrue(context.getApplicationLifecycleListeners()[0] instanceof DubboContextListener);
-        tomcat.stop();
-        tomcat.destroy();
-    }
-
-    @Test
-    public void testMetadataComplete() throws Exception {
-        Tomcat tomcat = new Tomcat();
-        tomcat.setBaseDir("target/test-classes");
-        tomcat.setPort(12345);
-        StandardContext context = new StandardContext();
-        context.setName("test3");
-        context.setDocBase("test3");
-        context.setPath("/test3");
-        context.addLifecycleListener(new ContextConfig());
-        tomcat.getHost().addChild(context);
-        tomcat.start();
-        // there should be no application listeners
-        Assert.assertEquals(0, context.getApplicationLifecycleListeners().length);
-        tomcat.stop();
-        tomcat.destroy();
-    }
-
-}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListenerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListenerTest.java
deleted file mode 100644
index 9b953d5..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListenerTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.config.spring.initializer;
-
-import org.apache.dubbo.config.DubboShutdownHook;
-import org.apache.dubbo.bootstrap.DubboBootstrap;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-public class DubboApplicationListenerTest {
-
-    @Test
-    public void testTwoShutdownHook() {
-        DubboShutdownHook spyHook = Mockito.spy(DubboShutdownHook.getDubboShutdownHook());
-        ClassPathXmlApplicationContext applicationContext = getApplicationContext(spyHook, true);
-        applicationContext.refresh();
-        applicationContext.close();
-        // shutdown hook can't be verified, because it will executed after main thread has finished.
-        // so we can only verify it by manually run it.
-        try {
-            spyHook.start();
-            spyHook.join();
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-        Mockito.verify(spyHook, Mockito.times(2)).destroyAll();
-    }
-
-    @Test
-    public void testOneShutdownHook() {
-        DubboShutdownHook spyHook = Mockito.spy(DubboShutdownHook.getDubboShutdownHook());
-        ClassPathXmlApplicationContext applicationContext = getApplicationContext(spyHook, false);
-        applicationContext.refresh();
-        applicationContext.close();
-        Mockito.verify(spyHook, Mockito.times(1)).destroyAll();
-    }
-
-    private ClassPathXmlApplicationContext getApplicationContext(DubboShutdownHook hook, boolean registerHook) {
-        DubboBootstrap bootstrap = new DubboBootstrap(registerHook, hook);
-        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
-        applicationContext.addApplicationListener(new DubboApplicationListener(bootstrap));
-        return applicationContext;
-    }
-}
diff --git a/dubbo-container/dubbo-container-spring/pom.xml b/dubbo-container/dubbo-container-spring/pom.xml
index cbcc43e..987b2c9 100644
--- a/dubbo-container/dubbo-container-spring/pom.xml
+++ b/dubbo-container/dubbo-container-spring/pom.xml
@@ -38,10 +38,5 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-config-spring</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-container/dubbo-container-spring/src/main/java/org/apache/dubbo/container/spring/SpringContainer.java b/dubbo-container/dubbo-container-spring/src/main/java/org/apache/dubbo/container/spring/SpringContainer.java
index 9aa9ca5..c6ec474 100644
--- a/dubbo-container/dubbo-container-spring/src/main/java/org/apache/dubbo/container/spring/SpringContainer.java
+++ b/dubbo-container/dubbo-container-spring/src/main/java/org/apache/dubbo/container/spring/SpringContainer.java
@@ -19,7 +19,6 @@ package org.apache.dubbo.container.spring;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ConfigUtils;
-import org.apache.dubbo.config.spring.initializer.DubboApplicationListener;
 import org.apache.dubbo.container.Container;
 
 import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -44,10 +43,7 @@ public class SpringContainer implements Container {
         if (configPath == null || configPath.length() == 0) {
             configPath = DEFAULT_SPRING_CONFIG;
         }
-        context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"), false);
-        context.addApplicationListener(new DubboApplicationListener());
-        context.registerShutdownHook();
-        context.refresh();
+        context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
         context.start();
     }
 
diff --git a/dubbo-distribution/pom.xml b/dubbo-distribution/pom.xml
index 4611320..c5c6f0a 100644
--- a/dubbo-distribution/pom.xml
+++ b/dubbo-distribution/pom.xml
@@ -251,11 +251,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-bootstrap</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>hessian-lite</artifactId>
         </dependency>
diff --git a/pom.xml b/pom.xml
index 5882557..8f3c0e5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -139,7 +139,6 @@
         <module>dubbo-demo</module>
         <module>dubbo-plugin</module>
         <module>dubbo-serialization</module>
-        <module>dubbo-bootstrap</module>
         <module>dubbo-compatible</module>
         <module>dubbo-dependencies-bom</module>
         <module>dubbo-bom</module>