boot spring 没有父子容器_Spring 系列(二):Spring MVC的父子容器

e79797c7639a682c8454b49b3eaa35d1.png

1.背景

在使用Spring MVC时候大部分同学都会定义两个配置文件,一个是Spring的配置文件spring.xml,另一个是Spring MVC的配置文件spring-mvc.xml。

在这里给大家抛个问题,如果在spring.xml和spring-mvc.xml文件中同时定义一个相同id的单例bean会怎样呢?大家可以先思考一下再继续往下看。

我做了个实验,结论是:容器中会同时存在两个相同id 的bean,而且使用起来互不干扰。

这是为什么呢?学过Spring的同学肯定会质疑,众所周知id是bean的唯一标示,怎么可能同时存在两个相同id的bean呢?是不是我在胡扯呢?

原谅我在这和大家卖了个关子,其实大家说的都没错,因为这里涉及到Spring MVC父子容器的知识点。

这个知识点是:在使用Spring MVC过程中会存在Spring MVC 、Spring两个IOC容器,且Spring MVC是Spring的子容器。

那这个父子容器到底是什么呢?

为了保证我所说的权威性,而不是知识的二道贩子,我将从Spring 官方文档和源码两方面展开介绍。

2.Spring MVC父子容器

2.1 web.xml配置

还是先找程序入口,查看web.xml配置文件,找到Spring MVC相关配置。

<servlet><servlet-name>spring-mvc</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>

配置很简单,只是配置了一个类型为DispatcherServlet类型的Servlet,并设置了初始化参数。那DispatcherServlet是什么呢?

2.2 DispatcherServlet类介绍

查看API文档

74e3f3ff36d48fdc40e2f9b2e29775e3.png

从继承图看出最终继承自HttpServlet,其实就是一个普通的Servlet。那为什么这个Servlet就能完成Spring MVC一系列复杂的功能呢?继续往下看。

2.3 DispatcherServlet工作流程

769ff1f7df0de658847cabb78e304013.png

DispatcherServlet工作流程如下:

(1) 所有请求先发到DispacherServlet 。

(2) DispacherServlet根据请求地址去查询相应的Controller,然后返回给DispacherServlet。

(3) DispacherServlet得到Controller后,让Controler处理相应的业务逻辑。

(4) Controler处理处理完后将结果返回给DispacherServlet。

(5) DispacherServlet把得到的结果用视图解析器解析后获得对应的页面。

(6) DispacherServlet跳转到解析后的页面。

在整个过程中DispatcherServlet承当了一个中心控制器的角色来处理各种请求。

2.4 DispatcherServlet上下文继承关系

2384a12957435ba27d4af611e1b5d008.png

上图来自Spring官网:

https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html

从图中可以看到DispatcherServlet里面有一个 Servlet WebApplicationContext,继承自 Root WebApplicationContext。

从上篇文章中我们知道WebApplicationContext其实就是一个IOC容器,root WebApplicationContext是Spring容器。

这说明DispatcherServlet中里创建了一个IOC容器并且这个容器继承了Spring 容器,也就是Spring的子容器。

而且官方文档中还有如下一段文字描述:

For many applications, having a single WebApplicationContext is simple and suffices. It is also possible to have a context hierarchy where one root WebApplicationContext is shared across multiple DispatcherServlet (or other Servlet) instances, each with its own child WebApplicationContext configuration. See Additional Capabilities of the ApplicationContext for more on the context hierarchy feature.The root WebApplicationContext typically contains infrastructure beans, such as data repositories and business services that need to be shared across multiple Servlet instances.
Those beans are effectively inherited and can be overridden (that is, re-declared) in the Servlet-specific child WebApplicationContext, which typically contains beans local to the given Servlet.

结合图和上述文字我们可以得出以下信息:

  1. 应用中可以包含多个IOC容器。
  2. DispatcherServlet的创建的子容器主要包含Controller、view resolvers等和web相关的一些bean。
  3. 父容器root WebApplicationContex主要包含包含一些基础的bean,比如一些需要在多个servlet共享的dao、service等bean。
  4. 如果在子容器中找不到bean的时候可以去父容器查找bean。

看到这里也许大家心中也许就明白文章开头中我说的Spring MVC中的父子容器了,对那个问题也有了自己的判断和答案。

当然文章还没有结束,毕竟这还仅限于对官方文档的理解,为了进一步验证,我们拿出终极武器:

阅读源码!

2.5 DispatcherServlet源码分析

本小节我们分为Spring MVC容器的创建和bean的获取两部分进行分析。

2.5.1 Spring MVC容器的创建

前面分析到DispatcherServlet本质上还是一个Servlet ,既然是Servlet ,了解Servlet生命周期的同学都知道Web 容器装载Servlet第一步是执行init()函数,因此以DispatcherServlet 的init函数为突破口进行分析。

@Override
public final void init() throws ServletException {// 1.读取init parameters 等参数,其中就包括设置contextConfigLocation PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);//2.初始化servlet中使用的beaninitServletBean();
}

在第1步读取init parameter的函数最终会调用setContextConfigLocation()设置配置文件路径。此处重点介绍initServletBean(),继续跟踪。

Override
protected final void initServletBean() throws ServletException {//初始化webApplicationContextthis.webApplicationContext = initWebApplicationContext();
}
protected WebApplicationContext initWebApplicationContext() {//1.获得rootWebApplicationContextWebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;//2.如果还没有webApplicatioinContext,创建webApplicationContextif (wac == null) {//创建webApplicationContextwac = createWebApplicationContext(rootContext);}return wac;
}

可以看到上面初始化webApplicationContext分为2步。

(1)获取父容器rootWebApplicationContext。

(2)创建子容器。

我们先看看rootWebApplicationContext是如何获取的。

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {Object attr = sc.getAttribute(attrName);return (WebApplicationContext) attr;
}

从上面代码中我没看到是从ServletContext获取了名为“WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE”的webApplicationContext。

认真看过上篇文章的同学应该记得这个属性是在Spring初始化 容器initWebApplicationContext()函数中的第3步设置进去的,取得的值即Spring IOC容器。

继续看如何创建webApplicationContext。

protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {return createWebApplicationContext((ApplicationContext) parent);
}
createWebApplicationContext(ApplicationContext parent) {//1.获取WebApplicationContext实现类,此处其实就是XmlWebApplicationContextClass<?> contextClass = getContextClass();//生成XmlWebApplicationContext实例ConfigurableWebApplicationContext wac =(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);//2.设置rootWebApplicationContext为父容器 wac.setParent(parent);//3.设置配置文件wac.setConfigLocation(getContextConfigLocation());//4.配置webApplicationContext.configureAndRefreshWebApplicationContext(wac);return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {//开始处理beanwac.refresh();
}

看到这里同学们有没有是曾相识的感觉。是的,这段逻辑和上篇文章创建Spring IOC的逻辑类似。

唯一不同的是在第2步会把Spring容器设置为自己的父容器。至于新建容器中bean的注册、解析、实例化等流程和Spring IOC容器一样都是交给XmlWebApplicationContext类处理,还没有掌握的同学可以看上篇文章。

2.5.2 Spring MVC Bean的获取

Spring MVC bean的获取其实我们在上篇文章已经介绍过,这次再单拎出来介绍一下,加深记忆。

protected <T> T doGetBean(// 获取父BeanFactoryBeanFactory parentBeanFactory = getParentBeanFactory();//如果父容器不为空,且本容器没有注册此bean就去父容器中获取beanif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// 如果父容器有该bean,则调用父beanFactory的方法获得该beanreturn (T) parentBeanFactory.getBean(nameToLookup,args);}//如果子容器注册了bean,执行一系列实例化bean操作后返回bean.//此处省略实例化过程.....return (T) bean;
}

上面代码就可以对应官方文档中“如果子容器中找不到bean,就去父容器找”的解释了。

3.小结

看完上面的介绍,相信大家对Spring MVC父子容器的概念都有所了解,现在我们分析文章开头的问题。

如果spring.xml和spring-mvc.xml定义了相同id的bean会怎样?假设id=test。

1.首先Spring 初始化,Spring IOC 容器中生成一个id为test bean实例。

2.Spring MVC开始初始化,生成一个id为test bean实例。

此时,两个容器分别有一个相同id的bean。那用起来会不会混淆?

答案是不会。

当你在Spring MVC业务逻辑中使用该bean时,Spring MVC会直接返回自己容器的bean。

当你在Spring业务逻辑中使用该bean时,因为子容器的bean对父亲是不可见的,因此会直接返回Spring容器中的bean。

虽然上面的写法不会造成问题。但是在实际使用过程中,建议大家都把bean定义都写在spring.xml文件中。

因为使用单例bean的初衷是在IOC容器中只存在一个实例,如果两个配置文件都定义,会产生两个相同的实例,造成资源的浪费,也容易在某些场景下引发缺陷。

4.尾声

现在大家基本都不使用在xml文件中定义bean的形式,而是用注解来定义bean,然后在xml文件中定义扫描包。如下:

<context:component-scan base-package="xx.xx.xx"/>

那如果在spring.xml和spring-mvc.xml配置了重复的包会怎样呢?

如果本文看明白的同学此时已经知道了答案。

答案是会在两个父子IOC容器中生成大量的相同bean,这就会造成内存资源的浪费。

也许有同学想到,那只在spring.xml中设置扫描包不就能避免这种问题发生了吗,答案是这样吗?

大家可以试试,这样会有什么问题。如果不行,那是为什么呢?

欲知分晓,敬请期待下篇分解!

如果想获得更多,欢迎关注公众号:七分熟pizza

公众号里我会分享更多技术以及职场方面的经验,大家有什么问题也可以直接在公众号向我提问交流。

a39d55d111fed42ff4bca168e6e39559.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/539798.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux创建目录【命令】

创建一个hello目录 mkdir /hello -------------------------------------- mkdir 相当于 make directory 相对路径&#xff1a;不从/开始&#xff0c;而是从当前目录开始&#xff0c;例如&#xff1a;data/ ,mnt/zmg绝对路径&#xff1a;从/开始的目录&#xff0c;就叫绝对…

手术后多久可以做胆摘除_近视手术后多久可以化眼妆?

今天小编就和大家聊聊&#xff0c;做完近视手术后&#xff0c;多久可以画眼妆&#xff1f;很多女生做完手术后&#xff0c;非常关心的一件事情就是多久可以化妆&#xff0c;化妆对手术效果有没有影响&#xff1f;今天&#xff0c;小编就此问题特别咨询了屈光手术专家。专家建议…

【CentOS 7LAMP架构4】,PHP5和PHP7的安装和配置#171219

2019独角兽企业重金招聘Python工程师标准>>> hellopasswd 安装PHP5 PHP官网www.php.net当前主流版本为5.6/7.1cd /usr/local/srcwget http://cn2.php.net/distributions/php-5.6.30.tar.bz2bzip2 -d php-5.6.30.tar.bz2tar xvf php-5.6.30.tarcd php-5.6.30./config…

Linux修改文件内容【命令】

在/opt/hello/world.txt文件中增加一行 hello linux world ! 方法一&#xff1a; 命令是&#xff1a;vi&#xff0c;vim vi 编辑器&#xff0c;相当于记事本&#xff0c;有编辑功能&#xff0c;但较弱 vim 复杂的编辑器&#xff0c;相当于windows的 editplus, notepad 等 …

hadoop中的9000端口代表什么_hadoop服务快速部署

这篇文章记录下针对不同的hadoop版本进行服务部署的过程&#xff0c;希望可以帮到你们安装docker hadoop2.7.0一键部署docker hadoop3.0.0集群(一个master 三个slave)安装docker hadoop 3.2.0 a、docker启动 b、docker compose方式启动安装hadoop 2.7.0版本安装命令docker run …

迷你世界电锯机器人_迷你世界:生产果冻的机器人,1分钟产出500个,10种口味随意挑选...

迷你世界是一款具有创意性和想象力的3D沙盒游戏&#xff0c;在游戏中玩家们总是能造出各种好玩的建筑物&#xff0c;毕竟背包里拥有成百上千的道具可供玩家们随意使用&#xff0c;而且一些道具相互叠加使用&#xff0c;还能产生更有趣的效果。近日就有一位大神使用多种道具&…

底层实现红黑树_图解:红黑树

注&#xff1a;本文比较硬核但是很值得大家花心思看完&#xff0c;看完你一定会有所收获的红黑树是面试中一个很经典也很有难度的知识点&#xff0c;网传字节跳动面试官最喜欢问这个问题。很多人会觉得这个知识点太难&#xff0c;不想花太多功夫去了解&#xff0c;也有人会认为…

处于停机等非正常状态_一文聊透 Dubbo 优雅停机

1 前言一年之前&#xff0c;我曾经写过一篇《研究优雅停机时的一点思考》&#xff0c;主要介绍了 kill -9&#xff0c;kill -15 两个 Linux 指令的含义&#xff0c;并且针对性的聊到了 Spring Boot 应用如何正确的优雅停机&#xff0c;算是本文的前置文章&#xff0c;如果你对上…

WinDbg 命令三部曲:(一)WinDbg 命令手册

《WinDbg 命令三部曲&#xff1a;&#xff08;一&#xff09;WinDbg 命令手册》《WinDbg 命令三部曲&#xff1a;&#xff08;二&#xff09;WinDbg SOS 扩展命令手册》《WinDbg 命令三部曲&#xff1a;&#xff08;三&#xff09;WinDbg SOSEX 扩展命令手册》导航目录 内置帮助…

华为手机的分类有何区别_“鸿蒙”系统能不能玩安卓游戏?如果能,它跟安卓系统有何区别?...

“鸿蒙”系统能不能玩安卓游戏&#xff1f;如果能&#xff0c;它跟安卓系统有何区别&#xff1f;笔者其实挺好奇一件事情&#xff0c;按理来说&#xff0c;华为即将推出“鸿蒙”系统&#xff0c;作为一款真正的国产系统&#xff0c;笔者肯定是要支持的&#xff0c;毕竟我自己使…

200t不稳定_技术革新!将不可能变为可能 这家企业是怎么做到的?

据水泥人网了解&#xff0c;每年的第四季度是整个水泥行业的高峰期&#xff0c;尤其是北方地区各大水泥集团都将会进入错峰停产和检修期&#xff0c;烧成技术改造往往是水泥企业技改过程最为重要的环节&#xff0c;如何做好烧成技术改造成为水泥企业必须要面对的问题。针对目前…

取消计算机触摸板,笔记本电脑触摸板如何打开和关闭

笔记本电脑触摸板怎么打开和关闭&#xff1f;现在用笔记本的用户都越来越多了&#xff0c;现在也有人把笔记本当电视使了。就是电视上看得到用笔记本联网也是能看到&#xff0c;电视看不到的笔记本电脑也能看到。但是笔记本上面有一个触摸板&#xff0c;现相信大家都用过。可是…

QQ显示服务器繁忙2013,在QQ空间发表日志的之后为什么样总是显示“服务器繁忙”?...

据小米方面介绍&#xff0c;小米手机认证空间帐号自2013年5月21日开通以来&#xff0c;框架&#xff0c;8mm加厚钢化玻璃&#xff0c;15mm防火板材质机壳3、在QQ空间发表日志的之后为什么总是显示“服务器繁忙”&#xff0c;发表不了日志&#xff1f;这个难题在我家电脑下终于存…

oracle更改编码

背景&#xff1a;win764bit英文操作系统&#xff08;支持中文&#xff09;   oracle11G默认安装   从ZHS16GBK字符集导入数据库表现&#xff1a;plsql显示为乱码解决&#xff1a;1、查看并更改数据库的编码为ZHS16GBK $sqlplus system/oracleSQL> select * from v$nls…

she is so css什么意思,输入she is so什么意思 微信she is so什么梗

最近很多人都在微信玩she is so的小游戏&#xff0c;会出现很多不同的形容词很有趣&#xff0c;适合好友之间一起玩。而不少人也不明白输入she is so是什么意思&#xff1f;该怎么玩呢&#xff1f;下文具体介绍。微信输入she is so是什么意思在微信聊天对话框中输入she /he is …

vs2017下开发C++MFC动态库实现

2019独角兽企业重金招聘Python工程师标准>>> 今天无意间浏览了一些关于vs2017新功能的介绍&#xff0c;特别是微软发部了Visual Studio Installer&#xff0c;这个集成安装工具简约的操作风格&#xff0c;丰富vs开发内容&#xff0c;真正打通了开发的“最后一公里”…

hadoop为什么出现

在很多领域里面&#xff0c;在现在这个时代下面&#xff0c;很多公司产生的数据太多了&#xff0c;数据量太大了。用原来的技术去做&#xff0c;有种捉襟见肘的感觉&#xff0c;要么在性能上面&#xff0c;要么在速度上面遇到了瓶颈&#xff0c;这个时候需要新的技术来解决&…

微信视频开发jquery mobile

功能 微信企业号里开发一个微视频功能&#xff0c;用于播放视频。技术 J2EE&#xff0c;前端ui是jquerymobile&#xff0c;HTML5&#xff0c;CSS3&#xff0c;开源视频插件&#xff1a;mediaelement-and-player.min.js 插件官网&#xff1a;http://www.mediaelementjs.com/视…

eclipse中tomcat服务器locations不能修改,解决eclipse中Tomcat服务器的server location选项不能修改的问题...

解决eclipse中Tomcat服务器的server location选项不能修改的问题问题描述编辑tomcat服务器时&#xff0c;server locations无法编辑&#xff0c;如下图&#xff1a;解决方法在Eclipse菜单栏中选择window — show view — server 可以看到服务的面板&#xff0c;服务面板中可看到…

当create table as select 遇上大数据

统计24小时的红包感知专题&#xff0c;有1.5亿行以上的数据&#xff0c;Nokia给出的方法是先按小时执行算法&#xff0c;再汇总各个小时的执行结果。 算法中包含了大量的 sum(case when)计算。 专题里有5个小节&#xff0c;执行计划的时候&#xff0c;需要跑5次where条件不同…