欠伸展肢体,吟咏心自愉。这篇文章主要讲述扯谈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非常麻烦。不小心easy搞错,并且费心思。
一劳永逸的解决的方法: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会导致混乱,而没什么用。
【扯谈spring mvc之WebApplicationContext的继承关系】所以推荐把全部的Service/Controller都移到root WebApplicationContext中初始化。
推荐阅读
- 2017最新xcode打包APP详细图文
- Django打造在线教育平台_day_2(新建users app 编写models之扩展user表)
- android读取通讯录
- 预防 app crash 之 unrecognized selector
- 免费带项目,免费指导1~2年开发经验的Android程序员
- Eclipse项目转Android
- Android 设计模式
- Android Studio插件之sexy editor(设置AS背景)
- Android - 使用JD-GUI反编译Android代码