Spring-SpringMVC父子容器

转载自  Spring-SpringMVC父子容器

前言

Spring&SpringMVC作为bean管理容器和MVC默认框架,是大多数web应用都会选择的方案。在其使用过程中,尽管基于xml的配置bean管理的方式依然存在,但在很多情况下已经采用的强大的注解功能将其替代。实际项目中,Spring和SpringMVC同时配置,以及xml配置bean和注解的混合使用,会造成诸如bean重复加载、多次实例化、无法自动注入、配置不生效等奇怪的异常现象。其实,以上问题的大多数原因还是出在Spring容器的理解与使用上。

 

容器

Spring整体框架核心概念中,容器是核心思想,但在一个项目,容器不一定只有一个,Spring中可以包括多个容器,且容器间存在上下层框架。最常见的使用场景就是同时使用Spring和SpringMVC两个框架,Srping为父(根)容器,SpringMVC作为子容器。通常的使用过程中,Spring父容器对SpringMVC子容器中的bean是不可见的,而子容器对父容器的中bean却是可见的,这是这两种容器的默认规则。但是:

子容器对父容器中内容可见,不是默认规则

 

加载过程

web容器

对于一个web应用,需要将其部署在web容器中,web容器为其提供一个全局的ServletContext,并作为之后Spring容器提供宿主环境。

Spring根容器

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

1.web.xml中的contextLoaderListener在web容器启动时,会监听到web容器的初始化事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文作为根上下文,即WebApplicationContext。WebApplicationContext只是接口类,其实际的实现类是XmlWebApplicationContext。

2.此上下文即作为Spring根容器,其对应的bean定义的配置由web.xml中的context-param中的contextConfigLocation指定。根容器初始化完毕后,Spring以

WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE

为属性Key,将其存储到ServletContext中,便于获取。

SpringMVC子容器

<servlet>
    <servlet-name>XXXX</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
1.contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,servlet可以配置多个,加载顺序按照load-on-startup来执行。以最常见的DispatcherServlet为例,该servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的上下文,用以持有SpringMVC相关的bean。

2.之后先通过

WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE

先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的父上下文,然后建立DispatcherServlet自己的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,内容包括初始化处理器映射、视图解析等。该servlet自己持有的上下文默认实现类也是WebApplicationContext。

3.初始化完毕后,spring以与servlet的名字相关(此处并非简单以servlet名为Key,通过转换码生存)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的根上下文中持有的bean。

当然,在根容器创建与子容器创建之间,还会创建监听器、过滤器等,完整的加载顺序为:

ServletContext -> context-param -> listener-> filter -> servlet

由以上过程,即确定了一个bean的使用范围(该使用范围,是比bean的scope定义的singleton、prototype、request、session、global-session的五种作用域更上层的内容)。

 

容器布局

容器布局的根本是确定bean的使用范围。就Spring与SpringMVC布局,也大致分为了两种方向:

传统型

父容器:保存数据源、服务层、DAO层、事务的bean。

子容器:保存MVC相关的controller的bean。

概述:事务控制在服务层。由于父容器不能访问文容器中内容,事务的bean在父容器中,无法访问子容器中内容,就无法对子容器中controller进行AOP(事务),不过做为传统型方案,也没有必要这要做。

激进型

父容器:不关我事~

子容器:管理所有bean。

概述:不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载Spring的配置,不使用父容器,只使用一个DispatcherServlet,抛弃层次概念。

场景:在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo\po\bo)和jsp页面,在满足分层的前提下,做一些相对较小功能时会变得非常冗余,所以“激进型”方案就出现了,没有接口、没有Service层、可以没有众多的O(vo\po\bo),所有事务控制上升到controller层。

关于布局选择吗,引用一句很合景的总结:

大项目求稳,小项目求快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值