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

[incubator-dubbo] branch 2.6.x updated: merge https://github.com/apache/incubator-dubbo/pull/2725 (#2734)

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

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


The following commit(s) were added to refs/heads/2.6.x by this push:
     new f2d73f7  merge https://github.com/apache/incubator-dubbo/pull/2725 (#2734)
f2d73f7 is described below

commit f2d73f7914c03cc95b884b69b3e660ee0a7ae033
Author: Ian Luo <ia...@gmail.com>
AuthorDate: Mon Nov 5 15:24:29 2018 +0800

    merge https://github.com/apache/incubator-dubbo/pull/2725 (#2734)
    
    * merge https://github.com/apache/incubator-dubbo/pull/2725
    
    * fix UT failure
    
    * remove useless test
    
    * fix unit test failures
---
 all/pom.xml                                        |  10 +-
 dubbo-bootstrap/pom.xml                            |  45 ---------
 .../org/apache/dubbo/bootstrap/DubboBootstrap.java | 111 ---------------------
 .../com/alibaba/dubbo/config/ProtocolConfig.java   |  11 +-
 dubbo-config/dubbo-config-spring/pom.xml           |   7 +-
 .../dubbo/config/spring/AnnotationBean.java        |  23 ++---
 .../alibaba/dubbo/config/spring/ServiceBean.java   |  36 +------
 .../spring/extension/SpringExtensionFactory.java   |  25 +++++
 .../spring/status/DataSourceStatusChecker.java     |  10 +-
 .../config/spring/status/SpringStatusChecker.java  |  10 +-
 .../dubbo/config/spring/util/BeanFactoryUtils.java |  58 +++++++++++
 .../DubboApplicationContextInitializer.java        |  39 --------
 .../initializer/DubboApplicationListener.java      |  49 ---------
 .../src/main/resources/META-INF/web-fragment.xml   |  22 ----
 .../initializer/DubboApplicationListenerTest.java  |  61 -----------
 .../spring/status/DataSourceStatusCheckerTest.java |  11 +-
 .../spring/status/SpringStatusCheckerTest.java     |  13 ++-
 .../DubboApplicationContextInitializerTest.java    |  87 ----------------
 dubbo-container/dubbo-container-spring/pom.xml     |   7 +-
 .../dubbo/container/spring/SpringContainer.java    |   6 +-
 pom.xml                                            |   1 -
 21 files changed, 142 insertions(+), 500 deletions(-)

diff --git a/all/pom.xml b/all/pom.xml
index 3988449..1de0578 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -321,13 +321,6 @@
         </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>
             <scope>compile</scope>
             <optional>true</optional>
@@ -424,7 +417,6 @@
                                     <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>
@@ -588,4 +580,4 @@
             </build>
         </profile>
     </profiles>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml
deleted file mode 100644
index ae6440a..0000000
--- a/dubbo-bootstrap/pom.xml
+++ /dev/null
@@ -1,45 +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>com.alibaba</groupId>
-        <version>2.6.5-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>
\ 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 37ec8a3..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 com.alibaba.dubbo.config.DubboShutdownHook;
-import com.alibaba.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/com/alibaba/dubbo/config/ProtocolConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java
index b901bed..4952dfe 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
@@ -459,13 +459,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 7697f6f..6284abc 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -36,11 +36,6 @@
             <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>
@@ -167,4 +162,4 @@
             -->
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java
index 6da7ba8..722c6d0 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java
@@ -28,7 +28,6 @@ import com.alibaba.dubbo.config.ModuleConfig;
 import com.alibaba.dubbo.config.MonitorConfig;
 import com.alibaba.dubbo.config.ProtocolConfig;
 import com.alibaba.dubbo.config.ProviderConfig;
-import com.alibaba.dubbo.config.ReferenceConfig;
 import com.alibaba.dubbo.config.RegistryConfig;
 import com.alibaba.dubbo.config.ServiceConfig;
 import com.alibaba.dubbo.config.annotation.Reference;
@@ -112,17 +111,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 {
@@ -131,6 +129,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/com/alibaba/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java
index 6174d1b..4a73082 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java
@@ -38,13 +38,13 @@ import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.ApplicationEventPublisherAware;
 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 com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.addApplicationListener;
+
 /**
  * ServiceFactoryBean
  *
@@ -56,8 +56,6 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
 
     private static final long serialVersionUID = 213195494150089726L;
 
-    private static transient ApplicationContext SPRING_CONTEXT;
-
     private final transient Service service;
 
     private transient ApplicationContext applicationContext;
@@ -78,34 +76,11 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
         this.service = service;
     }
 
-    public static ApplicationContext getSpringContext() {
-        return SPRING_CONTEXT;
-    }
-
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) {
         this.applicationContext = applicationContext;
         SpringExtensionFactory.addApplicationContext(applicationContext);
-        if (applicationContext != null) {
-            SPRING_CONTEXT = applicationContext;
-            try {
-                Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // backward compatibility to spring 2.0.1
-                method.invoke(applicationContext, new Object[]{this});
-                supportedApplicationListener = true;
-            } catch (Throwable t) {
-                if (applicationContext instanceof AbstractApplicationContext) {
-                    try {
-                        Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // backward compatibility to spring 2.0.1
-                        if (!method.isAccessible()) {
-                            method.setAccessible(true);
-                        }
-                        method.invoke(applicationContext, new Object[]{this});
-                        supportedApplicationListener = true;
-                    } catch (Throwable t2) {
-                    }
-                }
-            }
-        }
+        supportedApplicationListener = addApplicationListener(applicationContext, this);
     }
 
     @Override
@@ -303,9 +278,8 @@ 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 call unexport() here, see
+        // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener
     }
 
     // merged from dubbox
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java
index 8673b39..5cbc06e 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java
@@ -21,9 +21,14 @@ 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.config.DubboShutdownHook;
+import com.alibaba.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;
 
@@ -35,14 +40,21 @@ public class SpringExtensionFactory implements ExtensionFactory {
 
     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) {
         contexts.remove(context);
     }
 
+    public static Set<ApplicationContext> getContexts() {
+        return contexts;
+    }
+
     // currently for test purpose
     public static void clearContexts() {
         contexts.clear();
@@ -83,4 +95,17 @@ 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/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java
index fd0e32d..32baa41 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java
@@ -21,8 +21,8 @@ import com.alibaba.dubbo.common.logger.Logger;
 import com.alibaba.dubbo.common.logger.LoggerFactory;
 import com.alibaba.dubbo.common.status.Status;
 import com.alibaba.dubbo.common.status.StatusChecker;
-import com.alibaba.dubbo.config.spring.ServiceBean;
 
+import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
 import org.springframework.context.ApplicationContext;
 
 import javax.sql.DataSource;
@@ -42,7 +42,13 @@ public class DataSourceStatusChecker implements StatusChecker {
     @Override
     @SuppressWarnings("unchecked")
     public Status check() {
-        ApplicationContext context = ServiceBean.getSpringContext();
+        ApplicationContext context = null;
+        for (ApplicationContext c : SpringExtensionFactory.getContexts()) {
+            if (c != null) {
+                context = c;
+                break;
+            }
+        }
         if (context == null) {
             return new Status(Status.Level.UNKNOWN);
         }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java
index f722c91..f80b5e6 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java
@@ -21,8 +21,8 @@ import com.alibaba.dubbo.common.logger.Logger;
 import com.alibaba.dubbo.common.logger.LoggerFactory;
 import com.alibaba.dubbo.common.status.Status;
 import com.alibaba.dubbo.common.status.StatusChecker;
-import com.alibaba.dubbo.config.spring.ServiceBean;
 
+import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.Lifecycle;
 
@@ -38,7 +38,13 @@ public class SpringStatusChecker implements StatusChecker {
 
     @Override
     public Status check() {
-        ApplicationContext context = ServiceBean.getSpringContext();
+        ApplicationContext context = null;
+        for (ApplicationContext c : SpringExtensionFactory.getContexts()) {
+            if (c != null) {
+                context = c;
+                break;
+            }
+        }
         if (context == null) {
             return new Status(Status.Level.UNKNOWN);
         }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java
new file mode 100644
index 0000000..13a3011
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util;
+
+import org.springframework.beans.factory.BeanFactory;
+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;
+
+/**
+ * {@link BeanFactory} Utilities class
+ *
+ * @see BeanFactory
+ * @see ConfigurableBeanFactory
+ * @see org.springframework.beans.factory.BeanFactoryUtils
+ */
+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/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/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 220874a..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.springframework.web.context.ContextLoaderListener</listener-class>
-    </listener>
-
-</web-fragment>
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListenerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListenerTest.java
deleted file mode 100644
index 9220ce9..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/initializer/DubboApplicationListenerTest.java
+++ /dev/null
@@ -1,61 +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 com.alibaba.dubbo.config.spring.initializer;
-
-import com.alibaba.dubbo.config.DubboShutdownHook;
-
-import org.apache.dubbo.bootstrap.DubboBootstrap;
-import org.apache.dubbo.config.spring.initializer.DubboApplicationListener;
-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-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusCheckerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusCheckerTest.java
index 178f32c..264a843 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusCheckerTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusCheckerTest.java
@@ -19,10 +19,13 @@ package com.alibaba.dubbo.config.spring.status;
 import com.alibaba.dubbo.common.status.Status;
 import com.alibaba.dubbo.config.spring.ServiceBean;
 
+import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Answers;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.springframework.context.ApplicationContext;
 
 import javax.sql.DataSource;
@@ -47,11 +50,17 @@ public class DataSourceStatusCheckerTest {
 
     @Before
     public void setUp() throws Exception {
+        SpringExtensionFactory.clearContexts();
         initMocks(this);
         this.dataSourceStatusChecker = new DataSourceStatusChecker();
         new ServiceBean<Object>().setApplicationContext(applicationContext);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        Mockito.reset(applicationContext);
+    }
+
     @Test
     public void testWithoutApplicationContext() {
         Status status = dataSourceStatusChecker.check();
@@ -98,4 +107,4 @@ public class DataSourceStatusCheckerTest {
 
         assertThat(status.getLevel(), is(Status.Level.ERROR));
     }
-}
\ No newline at end of file
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/SpringStatusCheckerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/SpringStatusCheckerTest.java
index 39f9125..cc90388 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/SpringStatusCheckerTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/status/SpringStatusCheckerTest.java
@@ -19,9 +19,12 @@ package com.alibaba.dubbo.config.spring.status;
 import com.alibaba.dubbo.common.status.Status;
 import com.alibaba.dubbo.config.spring.ServiceBean;
 
+import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.Lifecycle;
 
@@ -44,6 +47,12 @@ public class SpringStatusCheckerTest {
         new ServiceBean<Object>().setApplicationContext(applicationContext);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        SpringExtensionFactory.clearContexts();
+        Mockito.reset(applicationContext);
+    }
+
     @Test
     public void testWithoutApplicationContext() {
         Status status = springStatusChecker.check();
@@ -53,6 +62,7 @@ public class SpringStatusCheckerTest {
 
     @Test
     public void testWithLifeCycleRunning() {
+        SpringExtensionFactory.clearContexts();
         ApplicationLifeCycle applicationLifeCycle = mock(ApplicationLifeCycle.class);
         new ServiceBean<Object>().setApplicationContext(applicationLifeCycle);
         given(applicationLifeCycle.getConfigLocations()).willReturn(new String[]{"test1", "test2"});
@@ -66,6 +76,7 @@ public class SpringStatusCheckerTest {
 
     @Test
     public void testWithoutLifeCycleRunning() {
+        SpringExtensionFactory.clearContexts();
         ApplicationLifeCycle applicationLifeCycle = mock(ApplicationLifeCycle.class);
         new ServiceBean<Object>().setApplicationContext(applicationLifeCycle);
         given(applicationLifeCycle.isRunning()).willReturn(false);
@@ -78,4 +89,4 @@ public class SpringStatusCheckerTest {
     interface ApplicationLifeCycle extends Lifecycle, ApplicationContext {
         String[] getConfigLocations();
     }
-}
\ No newline at end of file
+}
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 b5b8f8c..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java
+++ /dev/null
@@ -1,87 +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 1 application listener
-        Assert.assertEquals(1, 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
-        Assert.assertEquals(1, 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 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-container/dubbo-container-spring/pom.xml b/dubbo-container/dubbo-container-spring/pom.xml
index 0af93dc..642ef31 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>com.alibaba</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/com/alibaba/dubbo/container/spring/SpringContainer.java b/dubbo-container/dubbo-container-spring/src/main/java/com/alibaba/dubbo/container/spring/SpringContainer.java
index b5866f5..d21f3a5 100644
--- a/dubbo-container/dubbo-container-spring/src/main/java/com/alibaba/dubbo/container/spring/SpringContainer.java
+++ b/dubbo-container/dubbo-container-spring/src/main/java/com/alibaba/dubbo/container/spring/SpringContainer.java
@@ -21,7 +21,6 @@ import com.alibaba.dubbo.common.logger.LoggerFactory;
 import com.alibaba.dubbo.common.utils.ConfigUtils;
 import com.alibaba.dubbo.container.Container;
 
-import org.apache.dubbo.config.spring.initializer.DubboApplicationListener;
 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/pom.xml b/pom.xml
index f12a635..f5a85b1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,7 +138,6 @@
         <module>dubbo-demo</module>
         <module>dubbo-plugin</module>
         <module>dubbo-serialization</module>
-        <module>dubbo-bootstrap</module>
         <module>dependencies-bom</module>
         <module>bom</module>
         <module>all</module>