扯谈spring mvc之WebApplicationContext的继承关系

简介: spring mvc里的root/child WebApplicationContext的继承关系 在传统的spring mvc程序里会有两个WebApplicationContext,一个是parent,从applicationContext.xml里加载的,一个是child,从servlet-context.xml里加载的。

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

其中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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果不这样子分别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

 

相关文章
|
6天前
|
设计模式 前端开发 Java
初识Spring MVC
初识Spring MVC
11 0
|
6天前
|
前端开发 Java 应用服务中间件
Spring MVC框架概述
Spring MVC 是一个基于Java的轻量级Web框架,采用MVC设计模型实现请求驱动的松耦合应用开发。框架包括DispatcherServlet、HandlerMapping、Handler、HandlerAdapter、ViewResolver核心组件。DispatcherServlet协调这些组件处理HTTP请求和响应,Controller处理业务逻辑,Model封装数据,View负责渲染。通过注解@Controller、@RequestMapping等简化开发,支持RESTful请求。Spring MVC具有清晰的角色分配、Spring框架集成、多种视图技术支持以及异常处理等优点。
12 1
|
8天前
|
监控 前端开发 Java
SpringBoot与SpringMVC有哪些区别?
SpringBoot和SpringMVC是Java开发中常用的两个框架,它们都是由Spring框架所提供的,但在功能和使用方式上有着一些区别。
22 2
|
1月前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
1月前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
1月前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
33 3
|
1月前
|
前端开发 Java 容器
家族传承:Spring MVC中父子容器的搭建与管理指南
家族传承:Spring MVC中父子容器的搭建与管理指南
26 3
|
1月前
|
前端开发 Java API
头头是道:揭示Spring MVC如何获取和处理请求头数据
头头是道:揭示Spring MVC如何获取和处理请求头数据
26 1
|
1月前
|
前端开发 Java API
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
18 3
|
1月前
|
前端开发 Java Spring
转换之术:解析Spring MVC中类型转换器的实际运用
转换之术:解析Spring MVC中类型转换器的实际运用
22 0