简述:
在tomcat启动控制台输入如下信息:
信息: Initializing Spring root WebApplicationContext
2017-10-22 20:20:02,785 INFO - org.springframework.web.context.ContextLoader[272] - Root WebApplicationContext: initialization started
......
2017-10-22 20:20:03,562 INFO - org.springframework.web.context.ContextLoader[301] - Root WebApplicationContext: initialization completed in 775 ms
......
信息: Initializing Spring FrameworkServlet 'springMVC'
2017-10-22 20:20:03,866 INFO - org.springframework.web.servlet.FrameworkServlet[444] - FrameworkServlet 'springMVC': initialization started
......
2017-10-22 20:20:07,844 INFO - org.springframework.web.servlet.FrameworkServlet[463] - FrameworkServlet 'springMVC': initialization completed in 3978 ms
.......
其中:Root WebApplicationContext 是父,由listener加载,是web根
FrameworkServlet 是子,有servlet加载, 和根是父子关系。
下面代码试运行一下:
WebApplicationContext root = ContextLoader.getCurrentWebApplicationContext();
ServletContext servletContext = root.getServletContext();
// true
System.out.println(root == servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE));
// true
System.out.println(root == WebApplicationContextUtils.getWebApplicationContext(servletContext));
WebApplicationContext child = (WebApplicationContext) request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// false
System.out.println("root:" + root.containsLocalBean("myService"));
// true
System.out.println("root:" + root.containsLocalBean("firstController"));
// false
System.out.println("child:" + child.containsLocalBean("myService"));
// true
System.out.println("child:"+ child.containsLocalBean("firstController"));
// true
System.out.println("is parent==" + (child.getParent() == root));
======================================================
在传统的spring mvc程序里会有两个WebApplicationContext
,一个是parent,从applicationContext.xml
里加载的,一个是child,从servlet-context.xml
里加载的。
两者是继承关系,child WebApplicationContext 可以通过getParent()
函数获取到root WebApplicationContext。
简单地说child WebApplicationContext里的bean可以注入root WebApplicationContext里的bean,而parent WebApplicationContext的bean则不能注入child WebApplicationContext里的bean。
一个典型的web.xml的内容是:
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/applicationContext.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
其中root WebApplicationContext是通过listener初始化的,child WebApplicationContext是通过servlet初始化的。
而在applicationContext.xml
里通常只component-scan非Controller的类,如:
<context:component-scan base-package="io.github.test">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" />
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" /> </context:component-scan>
在servlet-context.xml
里通常只component-scan Controller类,如:
<context:component-scan base-package="io.github.test.web" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
如果不这样子分别component-scan的话,可能会出现Bean重复初始化的问题。
上面是Spring官方开始时推荐的做法。
root/child WebApplicationContext继承关系带来的麻烦
root WebApplicationContext里的bean可以在不同的child WebApplicationContext里共享,而不同的child WebApplicationContext里的bean区不干扰,这个本来是个很好的设计。
但是实际上有会不少的问题:
* 不少开发者不知道Spring mvc里分有两个WebApplicationContext,导致各种重复构造bean,各种bean无法注入的问题。
* 有一些bean,比如全局的aop处理的类,如果先root WebApplicationContext里初始化了,那么child WebApplicationContext里的初始化的bean就没有处理到。如果在child WebApplicationContext里初始化,在root WebApplicationContext里的类就没有办法注入了。
* 区分哪些bean放在root/child很麻烦,不小心容易搞错,而且费心思。
一劳永逸的解决办法:bean都由root WebApplicationContext加载
在一次配置metrics-spring时,对配置@EnableMetrics
配置在哪个WebApplicationContext里,感到很蛋疼。最终决定试下把所有的bean,包括Controller都移到root WebApplicationContext,即applicationContext.xml
里加载,而servlet-context.xml
里基本是空的。结果发现程序运行完全没问题。
后面在网上搜索了下,发现有一些相关的讨论:
http://forum.spring.io/forum/spring-projects/container/89149-servlet-context-vs-application-context
spring boot里的做法
在spring boot里默认情况下不需要component-scan的配置,于是猜测在Spring boot里是不是只有一个WebApplicationContext?
后面测试下了,发现在spring boot里默认情况下的确是只有一个WebApplicationContext:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
,所以在spring boot里省事了很多。
总结
spring 的ApplicationContext继承机制是一个很好的设计,在很多其它地方都可以看到类似的思路,比如Java的class loader。但是在大部分spring web程序里,实际上只要一个WebApplicationContext就够了。如果分开Root/Child WebApplicationContext会导致混乱,而没什么用。
所以推荐把所有的Service/Controller都移到root WebApplicationContext中初始化。
来自: http://blog.csdn.net/hengyunabc/article/details/47072637
相关推荐
request.getSession().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, locale); return "redirect:/"; } } ``` 这个方法会将用户选择的语言存储在Session中,下次请求时,...
在Java开发领域,Spring、SpringMVC和MyBatis是三个非常重要的框架,它们共同构建了一个强大而灵活的Web应用程序栈。Spring作为一个全面的后端开发框架,提供了依赖注入(DI)和面向切面编程(AOP)等功能,极大地...
内容概要:本文档全面介绍了JavaWeb开发中的几个关键技术,包括Servlet与JSP的基础与深入分析,Spring MVC框架的解析与应用,以及JPA与Hibernate的结合使用。每个部分不仅阐述了技术的基本概念和工作原理,还涵盖了...
### SpringMVC 实现单个文件上传功能 #### 一、背景介绍 在现代Web应用开发中,文件上传是一项常见的需求。SpringMVC作为Spring框架的一部分,提供了强大的支持来处理文件上传任务。本文将详细介绍如何在SpringMVC...
在Spring与SpringMVC的整合应用中,它们之间存在着一种特殊的父子容器关系,这种关系对于理解和优化应用的配置及管理非常重要。 首先,让我们深入理解Spring容器。Spring容器主要分为两种类型:ApplicationContext...
在SpringMVC的配置文件中可以添加<mvc:default-servlet-handler/>,这允许SpringMVC使用默认的Servlet来处理静态文件请求。通过在web.xml文件中对默认Servlet进行映射(通常是url-pattern为/*),可以让默认Servlet...
在Spring MVC项目中,加载jar包中的Spring配置文件是一个常见的需求,特别是在进行SSM(Spring、Spring MVC、MyBatis)整合时。SSM框架的整合通常涉及到多个配置文件的组织和管理,其中一部分配置可能会被打包到独立...
Spring框架的核心在于IoC(Inversion of Control)容器,它通过读取XML配置文件来管理对象的生命周期和依赖关系。在Spring的资源配置文件(通常命名为`beans.xml`)中,我们可以定义Bean的实例化、初始化方法、属性...
3. **配置文件路径**:默认情况下,Spring会根据Servlet的名字来寻找配置文件,其默认路径和文件名为`dispatcherContext-servlet.xml`。如果希望使用自定义的配置文件路径,则需要在`<init-param>`中指定: ```xml ...
spring整合springmvc、mybatis的jar包和配置文件,spring整合springmvc、mybatis的jar包和配置文件,spring整合springmvc、mybatis的jar包和配置文件
在整合SpringMVC和Spring时,我们需要创建一个Spring的配置文件,通常命名为`applicationContext.xml`。这个文件定义了bean的配置,包括SpringMVC的DispatcherServlet配置、数据源、事务管理器、服务层接口及其实现...
在 `pom.xml` 文件中,我们需要添加 SpringMVC 和其他依赖库,例如 Servlet API 和 JSP API(这里使用的是 javax.* 版本,而不是 javax.servlet.*)。确保添加以下依赖: ```xml <!-- SpringMVC --> <groupId>...
"WEB-INF"目录是Web应用的标准结构之一,其中包含了web.xml配置文件,这是Web应用的部署描述符,用于配置Servlet、Filter、Listener等组件,以及类库(lib目录)和应用的视图资源(例如JSP文件)。 综上所述,...
Spring、SpringMVC和Mybatis是Java开发中最常用的三大开源框架,它们的整合使用,通常被称为SSM框架。这个框架组合提供了完整的后端服务解决方案,包括依赖注入(DI)、面向切面编程(AOP)、模型-视图-控制器(MVC...
- `<context-param>`和`<listener>`用于初始化Spring的全局上下文,`ContextLoaderListener`监听器会在服务器启动时加载`applicationContext.xml`配置文件,创建ApplicationContext。 4. **SpringMVC配置**...
Spring 和 SpringMVC 的配置加载顺序是理解这两个框架协同工作的重要方面。首先,DispatcherServlet 是 SpringMVC 的核心组件,它扮演着请求分发者的角色,确保请求被正确地路由到相应的处理器。DispatcherServlet ...
在IT行业中,Spring、SpringMVC和MyBatis是三个非常重要的开源框架,它们分别用于企业级应用的依赖管理、Web层控制以及数据访问。这三个框架的整合是Java开发中的常见实践,能够帮助开发者构建高效、灵活且易于维护...
Servlet、JSP和SpringMVC初学指南
最后,确保Web应用的web.xml配置文件中正确地加载了SpringMVC和Spring的配置文件,以及SpringMVC的DispatcherServlet。 **总结** SpringMVC+Spring+SpringJDBC的整合提供了一个高效、灵活的Web应用程序开发环境。...
SSM(Spring、SpringMVC和MyBatis)整合是Java Web开发中常见的技术栈,它结合了Spring框架的强大功能,SpringMVC的优雅请求处理,以及MyBatis的灵活数据库操作。本项目是一个入门级别的实例,旨在帮助初学者理解和...