扯谈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则不能注入chile 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就没有处理到。如果在chile 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中初始化。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 11:54:45

扯谈spring mvc之WebApplicationContext的继承关系的相关文章

Spring MVC 了解WebApplicationContext中特殊的bean类型

Spring MVC 了解WebApplicationContext中特殊的bean类型 Spring的DispatcherServlet使用了特殊的bean来处理请求.渲染视图等,这些特定的bean是Spring MVC框架的一部分.如果你想指定使用哪个特定的bean,你可以在web应用上下文WebApplicationContext中简单地配置它们.当然这只是可选的,Spring MVC维护了一个默认的bean列表,如果你没有进行特别的配置,框架将会使用默认的bean.下一小节会介绍更多的细

深入Spring Boot:ClassLoader的继承关系和影响

前言 对spring boot本身启动原理的分析, Spring boot里的ClassLoader继承关系 可以运行下面提供的demo,分别在不同的场景下运行,可以知道不同场景下的Spring boot应用的ClassLoader继承关系. 分三种情况: 在IDE里,直接run main函数 则Spring的ClassLoader直接是SystemClassLoader.ClassLoader的urls包含全部的jar和自己的target/classes ========= Spring Bo

Spring MVC学习------------WebApplicationContext

父子上下文(WebApplicationContext) 如果你使用了listener监听器来加载配置,一般在Struts+Spring+Hibernate的项目中都是使用listener监听器的.如下 Java代码   <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> Spring会创建一

Spring mvc 上下文初始化过程

在软件开发的中,如果某些特性的使用比较普遍,那么这些特性往往可以作为平台特性来实现,通过对这些平台特性进行有效的封装,使其向其他应用开放.正是如此,Spring由于其IOC.AOP.事务处理.持久化驱动等特点,使得其起到了一个应用平台的作用.Spring MVC是Spring的一个重要的模块,其web应用的实现,是由Spring的来支撑的,Spring MVC的是实现也是依托再Spring平台提供的基础特性的.本文主要是介绍Spring mvc容器初始化的过程,从中可以看出Spring MVC的

spring mvc DispatcherServlet详解之前传---FrameworkServlet

做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationContext. 首先我们来了解applicationContext 和WebapplicationContext区别和联系吧 1. ApplicationContext和WebApplicationContext是继承关系 /** * Interface to provide configuration

浅析Spring MVC和Spring BOOT之间的简化小秘密

从Servlet技术到Spring和Spring MVC,开发Web应用变得越来越简捷.但是Spring和Spring MVC的众多配置有时却让人望而却步,相信有过Spring MVC开发经验的朋友能深刻体会到这一痛苦.因为即使是开发一个Hello-World的Web应用,都需要我们在pom文件中导入各种依赖,编写web.xml.spring.xml.springmvc.xml配置文件等.特别是需要导入大量的jar包依赖时,我们需要在网上查找各种jar包资源,各个jar间可能存在着各种依赖关系,

从Spring MVC 到 Spring BOOT的简化道路

背景 从Servlet技术到Spring和Spring MVC,开发Web应用变得越来越简捷.但是Spring和Spring MVC的众多配置有时却让人望而却步,相信有过Spring MVC开发经验的朋友能深刻体会到这一痛苦.因为即使是开发一个Hello-World的Web应用,都需要我们在pom文件中导入各种依赖,编写web.xml.spring.xml.springmvc.xml配置文件等. 特别是需要导入大量的jar包依赖时,我们需要在网上查找各种jar包资源,各个jar间可能存在着各种依

浅谈MVC, Spring MVC,

一个典型的java web 从架构上看起来应该是这个样子: 1. web浏览器发送http请求到服务端, 被controller(servlet)获取并进行处理. 2. Controller (Servlet)调用核心业务逻辑 model部分. 3. Model进行数据库存取操作, 并将操作结果返回给model. 4. Controller将业务逻辑处理结果交给view(JSP), 动态输出HTML内容. 5. 动态生成的HTML内容返回到浏览器中显示. Spring MVC提供了一个Dispa

Spring MVC源码——Root WebApplicationContext

目录 Spring MVC源码--Root WebApplicationContext 上下文层次结构 Root WebApplicationContext 初始化和销毁 ContextLoaderListener ContextLoader Servlet 3.0+ 中初始化 参考资料 Spring MVC源码--Root WebApplicationContext 打算开始读一些框架的源码,先拿 Spring MVC 练练手,欢迎点击这里访问我的源码注释. Spring MVC 的文档一开始