zoukankan      html  css  js  c++  java
  • 扯谈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会导致混乱,而没什么用。

    所以推荐把全部的Service/Controller都移到root WebApplicationContext中初始化。

  • 相关阅读:
    数据结构(四十)平衡二叉树(AVL树)
    数据结构(三十九)二叉排序树
    数据结构(三十八)静态查找表(顺序查找、二分查找、插值查找、斐波那契查找、线性索引查找)
    数据结构(三十七)查找的基本概念
    数据结构(三十六)关键路径
    数据结构(三十五)拓扑排序
    数据结构(三十四)最短路径(Dijkstra、Floyd)
    数据结构(三十三)最小生成树(Prim、Kruskal)
    字符串匹配算法之KMP
    最长公共子序列(Longest common subsequence)
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7069518.html
Copyright © 2011-2022 走看看