问题1
Controller被初始化两次。
配置文件
web.xml
<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
<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
<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代码
@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("--------------------------------------------------------");
}
}
}
启动项目后的打印日志:
信息: 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引起的初始化调用栈中有
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即可。
<context:component-scan base-package="com.jc.site" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
启动,Controller只初始化一次,且功能正常!
参考文档
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来响应 请求的。