Spring MVC项目中Controller初始化两次的问题分析

问题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://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来响应 请求的。


你可能感兴趣的:(Spring MVC项目中Controller初始化两次的问题分析)