扯谈spring mvc之WebApplicationContext的继承关系
spring mvc里的root/child WebApplicationContext的继承关系
在传统的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就够了。如果分开rott/child WebApplicationContext会导致混乱,而没什么用。
所以推荐把所有的Service/Controller都移到root WebApplicationContext中初始化。
http://blog.csdn.net/hengyunabc/article/details/47072637
扯谈spring mvc之WebApplicationContext的继承关系的更多相关文章
- Spring☞WebApplicationContext的继承关系
spring mvc里的root/child WebApplicationContext的继承关系 在传统的spring mvc程序里会有两个WebApplicationContext,一个是pare ...
- Spring MVC 了解WebApplicationContext中特殊的bean类型
Spring MVC 了解WebApplicationContext中特殊的bean类型 Spring的DispatcherServlet使用了特殊的bean来处理请求.渲染视图等,这些特定的bean ...
- 深入Spring Boot:ClassLoader的继承关系和影响
前言 对spring boot本身启动原理的分析, Spring boot里的ClassLoader继承关系 可以运行下面提供的demo,分别在不同的场景下运行,可以知道不同场景下的Spring bo ...
- 浅谈Spring MVC知识
关于MVC框架,我相信大家都不陌生,都会说也就是模型-视图-控制器这三层的框架结构,如果你参加面试的时候考官会问:“MVC框架是什么?你说一说.”其实我们都知道这个问题还需要问的,只要你是一个开发人员 ...
- Spring MVC学习------------WebApplicationContext
父子上下文(WebApplicationContext) 假设你使用了listener监听器来载入配置.一般在Struts+Spring+Hibernate的项目中都是使用listener监听器的. ...
- 深入分析Spring 与 Spring MVC容器
1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...
- spring mvc DispatcherServlet详解之前传---FrameworkServlet
做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...
- Spring mvc web 配置
Spring Framework本身没有Web功能, Spring MVC使用WebApplicationContext类扩展ApplicationContext ,使得拥有web功能.那么,Spri ...
- 深入分析Spring 与 Spring MVC容器(山东数漫江湖)
1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...
随机推荐
- 七牛云- Java 端 使用
项目 中需要把 图片放到 图片服务器上托管, 所以使用了七牛, 注册之后每个月 有免费100 万 次get请求,先说说怎么使用: 1 .注册, 获取自己的AK,SK
- leetcode第一刷_Interleaving String
有关这样的字符串的题真是层出不穷啊,并且他们都有这样一个特点,就是递归的思路如此简单,但一定超时! 这个时候,dp就朝我们缓缓走来.递归超,dp搞!这道题的状态转移方程还是比較好写的,用ispart[ ...
- Java之多线程断点下载的实现
RandomAccessFile类: 此类的实例支持对随机訪问文件的读取和写入.随机訪问文件的行为相似存储在文件系统中的一个大型 byte 数组. 存在指向该隐含数组.光标或索引,称为文件指针.输入操 ...
- Android源代码分析之Framework的MediaPlayer
在Android中MediaPlayer用来播放音频和视频文件,在这里分析下在Framework层中MediaPlayer是怎样调用的.MediaPlayer的代码位于:./frameworks/ba ...
- Web站点架构设计考虑的因素
转自http://blog.csdn.net/moshengtan/article/details/8990052 1 Web负载均衡 1.1 - 使用商业硬件实现 最经常使用的F5 与citr ...
- ios中框架介绍
ios中框架介绍 参考博客: 参考文章:框架介绍 框架介绍 框架就是一个目录,一个目录包含了共享库,访问共享库里面的代码的头文件,和其他的图片和声音的资源文件.一个共享库定义的方法和函数可以被应用程序 ...
- 详解Android Handler的使用-别说你不懂handler(转)
我们进行Android开发时,Handler可以说是使用非常频繁的一个概念,它的用处不言而喻.本文就详细介绍Handler的基本概念和用法. Handler的基本概念 Handler主 ...
- 【转】overload与override的区别
[转]overload与override的区别 override(重写,覆盖) 1.方法名.参数.返回值相同. 2.子类方法不能缩小父类方法的访问权限. 3.子类方法不能抛出比父类方法更多的异常(但子 ...
- ASP.NET生成压缩文件(rar打包)
首先引用ICSharpCode.SharpZipLib.dll,没有在这里下载:http://files.cnblogs.com/files/cang12138/ICSharpCode.SharpZi ...
- Linux命令--用户用户组管理
新增用户组 : groupadd groupadd [-g GID] 组名 不加-g 则按照系统默认的gid创建组,跟用户一样,gid也是从500开始的 修改用户组信息 : groupmod grou ...