问题1:Controller被初始化两次。
配置文件
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <context-param > <param-name > webAppRootKey</param-name > <param-value > testApp</param-value > </context-param > <context-param > <param-name > contextConfigLocation</param-name > <param-value > /WEB-INF/classes/META-INF/spring/core/applicationContext.xml</param-value > </context-param > <listener > <listener-class > com.jc.site.web.SystemContextListener</listener-class > </listener > <servlet > <servlet-name > dispatcher</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > /WEB-INF/classes/META-INF/spring/core/dispatcher-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcher</servlet-name > <url-pattern > *.html</url-pattern > </servlet-mapping >
applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <context:annotation-config /> <context:component-scan base-package ="com.jc.site" /> <bean id ="propertyConfigurer" class ="com.jc.site.common.util.PropertiesUtil" > <property name ="locations" > <list > <value > classpath:jdbc.properties</value > <value > classpath:system.properties</value > <value > classpath:redis.properties</value > </list > </property > </bean > <import resource ="classpath:META-INF/spring/db/jdbc/applicationContext_jdbc.xml" /> <import resource ="classpath*:META-INF/spring/springContext_*.xml" />
dispatcher-servlet.xml
1 2 3 4 5 6 7 8 <context:annotation-config /> <bean class ="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" > <property name ="order" value ="1" /> </bean > <context:component-scan base-package ="com.jc.site.controller" />
目标Controller代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Controller public class IndexController extends BaseController { public IndexController () { printStackTrace(); System.out.println("IndexController init....hashCode=" + this .hashCode()); } private static void printStackTrace () { StackTraceElement[] stackElements = new Throwable ().getStackTrace(); if (stackElements != null ) { System.out.println("--------------------------------------------------------" ); for (int i = 0 ; i < stackElements.length; i++) { System.out.println("\t" + stackElements[i]); } System.out.println("--------------------------------------------------------" ); } } }
启动项目后的打印日志:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 信息: Initializing Spring root WebApplicationContext -------------------------------------------------------- com.jc.site.controller.IndexController.printStackTrace(IndexController.java:59) com.jc.site.controller.IndexController.<init>(IndexController.java:21) …………………… org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) com.jc.site.web.SystemContextListener.contextInitialized(SystemContextListener.java:19) org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973) org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467) org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) java.util.concurrent.FutureTask.run(FutureTask.java:262) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) java.lang.Thread.run(Thread.java:745) -------------------------------------------------------- IndexController init....hashCode=2125761735 init UserDao... 2015-06-09 11:52:28,357 INFO (com.alibaba.druid.pool.DruidDataSource:652) - {dataSource-1} inited 六月 09, 2015 11:52:28 上午 org.apache.catalina.core.ApplicationContext log 信息: Initializing Spring FrameworkServlet 'dispatcher' -------------------------------------------------------- com.jc.site.controller.IndexController.printStackTrace(IndexController.java:59) com.jc.site.controller.IndexController.<init>(IndexController.java:21) …………………… org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665) org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:521) org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:462) org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136) javax.servlet.GenericServlet.init(GenericServlet.java:158) org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284) org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197) org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087) org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5210) org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5493) org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) java.util.concurrent.FutureTask.run(FutureTask.java:262) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) java.lang.Thread.run(Thread.java:745) -------------------------------------------------------- IndexController init....hashCode=638958293 六月 09, 2015 11:52:28 上午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandler ["http-apr-8080"] 六月 09, 2015 11:52:28 上午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandler ["ajp-apr-8009"] 六月 09, 2015 11:52:28 上午 org.apache.catalina.startup.Catalina start 信息: Server startup in 3616 ms
看日志发现调用栈 第一个是ContextLoaderListener初始化生成的,第二个是由GenericServlet初始化生成的。
第二个GenericServlet.java引起的初始化调用栈中有
1 2 3 org.springframework.web.servlet.DispatcherServlet.initHandlerMappings(DispatcherServlet.java:525) org.springframework.web.servlet.DispatcherServlet.initStrategies(DispatcherServlet.java:440) org.springframework.web.servlet.DispatcherServlet.onRefresh(DispatcherServlet.java:429)
可见是初始化Spring MVC的DispatcherServlet引起的。
SpringMVC的启动创建了两个applicationContext。参见:http://blog.csdn.net/madun/article/details/8988860/
Controller属于MVC层的,而applicationContext.xml属于Spring的。component-scan默认会加载内容包含Controller。
component-scan Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Spring-provided @Component, @Repository, @Service, and @Controller stereotypes will be detected.
所以只要在applicationContext的配置中剔除Controller即可。
1 2 3 <context:component-scan base-package ="com.jc.site" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan >
启动,Controller只初始化一次,且功能正常!
参考文档
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/FilterType.html
http://www.leveluplunch.com/blog/2014/08/30/exclude-filter-component-scan-spring/
http://blog.csdn.net/liuwenbo0920/article/details/7260013
http://www.cnblogs.com/zemliu/p/3201112.html
【遗留需要确认的问题】
既然Spring,SpringMVC中生成了两个不同的ApplicationContext,那一个http请求Spring是如何在这两个ApplicationContext中查找、获取 相应的BEAN来响应 请求的。