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
new file mode 100644
index 00000000000..35b2b70c2c2
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboContextListener.java
@@ -0,0 +1,72 @@
+/*
+ * 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/resources/META-INF/web-fragment.xml b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml
index c063bdf2f37..e1eef6ba0de 100644
--- 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
@@ -16,7 +16,7 @@
- org.springframework.web.context.ContextLoaderListener
+ org.apache.dubbo.config.spring.initializer.DubboContextListener
-
\ 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
index b5b8f8c9a9b..02dda03a7ac 100644
--- 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
@@ -38,8 +38,9 @@ public void testSpringContextLoaderListenerInWebXml() throws Exception {
context.addLifecycleListener(new ContextConfig());
tomcat.getHost().addChild(context);
tomcat.start();
- // there should be 1 application listener
- Assert.assertEquals(1, context.getApplicationLifecycleListeners().length);
+ // 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();
@@ -58,10 +59,10 @@ public void testNoListenerInWebXml() throws Exception {
context.addLifecycleListener(new ContextConfig());
tomcat.getHost().addChild(context);
tomcat.start();
- // there should be 1 application listener
+ // 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 ContextLoaderListener);
+ Assert.assertTrue(context.getApplicationLifecycleListeners()[0] instanceof DubboContextListener);
tomcat.stop();
tomcat.destroy();
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java
index 532d97b5473..c82fd4af615 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java
@@ -49,6 +49,7 @@ public class DataSourceStatusCheckerTest {
@Before
public void setUp() throws Exception {
+ SpringExtensionFactory.clearContexts();
initMocks(this);
this.dataSourceStatusChecker = new DataSourceStatusChecker();
new ServiceBean