SpringMVC父子容器详解 - 极悦
首页 课程 师资 教程 报名

SpringMVC父子容器详解

  • 2022-10-08 10:08:11
  • 1425次 极悦

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容器中,这个容器为它提供了一个全局的ServletContext,作为Spring容器的宿主环境。

Spring容器

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

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

2.这个context就是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都拥有自己的context,即拥有自己独立的bean空间,并且每个servlet共享同一个root context中持有的bean。

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

ServletContext -> 上下文参数 -> 监听器 -> 过滤器 -> servlet

通过以上流程,确定了一个bean的使用范围(使用范围高于bean的范围定义的singleton、prototype、request、session、global-session五个范围)。

容器布局

容器布局的本质是确定bean的使用范围。Spring和SpringMVC的布局大致可以分为两个方向:

传统的

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

子容器:持有MVC相关控制器的bean。

概述:事务控制在服务层。由于父容器无法访问文件容器中的内容,事务bean在父容器中,无法访问子容器中的内容,因此无法对子容器中的控制器进行AOP(事务)。

新的

父容器:不关我的事~

子容器:管理所有 bean。

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

场景:在一个以增删改查为主要业务的系统中,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上很多O(vo\po\bo)和jsp页面,在满足分层的前提下,做一些比较小的功能会变得很多余,于是出现了“激进”的方案。接口,没有Service层,不可能有很多O(vo\po\bo),所有的事务控制都上升到控制器层。

关于布局选择,我引用了一个很好的总结:

大项目求稳定,小项目求速度。

以上就是关于“SpringMVC父子容器详解”的介绍,大家如果想了解更多相关知识,不妨来关注一下本站的SpringMVC教程,里面还有更丰富的知识等着大家去学习,希望对大家能够有所帮助哦。

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交