Spiring父子容器
一、父子容器
通过HierarchicalBeanFactory接口,Spring的IoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,但父容器不能访问子容器的Bean。在容器内,Bean的id必须是唯一的,但子容器可以拥有一个和父容器id相同的Bean。父子容器层级体系增强了Spring容器架构的扩展性和灵活性,因为第三方可以通过编程的方式,为一个已经存在的容器添加一个或多个特殊用途的子容器,以提供一些额外的功能。
Spring使用父子容器实现了很多功能,比如在Spring MVC中,展现层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中。这样,展现层Bean就可以引用业务层和持久层的Bean,而业务层和持久层的Bean则看不到展现层的Bean。
二、spring的启动过程
spring的启动过程其实就是其IoC容器的启动过程,对于web程序,IoC容器启动过程即是建立上下文的过程。
首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;
其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;
再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有spring mvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是mlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。
三、父子容器的配置
1、父容器
web.xml中增加监听
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
监听器会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。
可以使用Spring提供的工具类取出上下文对象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);
2、子容器
web.xml中定义dispatcherServlet入口
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:config/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
dispatcherServlet是装载Controller的上下文。DispatcherServlet是一个Servlet,可以同时配置多个,每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。当一个Request对象产生时,会把这个子上下文对象(WebApplicationContext)保存在Request对象中,key是DispatcherServlet.class.getName() + ".CONTEXT"。
可以使用工具类取出上下文对象:RequestContextUtils.getWebApplicationContext(request);
四、实践
1、传统型
因为spring的context是父子容器,所以会产生冲突,由ServletContextListener产生的是父容器,springMVC产生的是子容器,子容器Controller进行扫描装配时装配了@Service注解的实例,此时得到的将是原样的Service(没有经过事务加强处理,故而没有事务处理能力,因为@Service注解的实例理应由父容器进行初始化以保证事务的增强处理)。 所以传统型将父容器和子容器各司其职:
父上下文容器中保存数据源、服务层、DAO层、事务的Bean。
子上下文容器中保存Mvc相关的Action的Bean.
事务控制在服务层。
在主容器中(applicationContext.xml),将Controller的注解排除掉
<context:component-scan base-package="com"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
上述的配置指定了Spring框架所扫描的注解不包括@Controller(也可以直接通过包名来指定),当然其他的配置文件(如:事务配置、AOP配置、定时任务等)可以通过<import />引入进来。
而在springMVC配置文件中将Service注解给去掉
<context:component-scan base-package="com"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
上面配置是指定了DispatcherServlet所创建的上下文只扫描控制层的beans,当然在dispatcher-servlet.xml中还可以指定视图解析、JSON转换、上传下载等配置信息。
2、激进型
没有接口、没有Service层、还可以没有众多的O(vo\po\bo)。那没有Service层事务控制在哪一层?只好上升的Action层。
由于父上下文容器不能访问子上下文容器中内容,事务的Bean在父上下文容器中,无法访问子上下文容器中内容,就无法对子上下文容器中Action进行AOP(事务)。解决方案是只使用子上下文容器,不要父上下文容器 。所以数据源、服务层、DAO层、事务的Bean、Action的Bean都放在子上下文容器中。就可以实现了,事务(注解事务)就正常工作了。这样才够激进。
总结:不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载spring的配置,不要父子上下文,只使用一个DispatcherServlet。
Spiring父子容器相关推荐
- 聊聊 SpringCloud 中的父子容器
点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 来源公号:吉姆餐厅ak 概述 在引入 SpringCloud 的项目中会多次创建 Spring 容 ...
- 面试高频题:Spring和SpringMvc父子容器你能说清楚吗
引言 以前写了几篇关于SpringBoot的文章<面试高频题:springBoot自动装配的原理你能说出来吗>.<保姆级教程,手把手教你实现一个SpringBoot的starter& ...
- boot spring 没有父子容器_Spring父子容器问题
这个问题老早就存在了,只是今天组长让我看AOP不生效的时候,才真实遇到这个问题,之前都是用的Spring Boot开发,不会存在这个问题. 问题描述 如果使用传统的方式来开发Spring项目,要部署在 ...
- Spring父子容器的关系分析--用实例说话
Spring中父子容器的实现实例Spring的父子容器可以通过ConfigurableApplicationContext或ConfigurableBeanFactory来实现,这两个接口中分别有se ...
- SpringMVC——自定义拦截器、异常处理以及父子容器配置
SpringMVC--自定义拦截器.异常处理以及父子容器配置 参考文章: (1)SpringMVC--自定义拦截器.异常处理以及父子容器配置 (2)https://www.cnblogs.com/so ...
- Spring和SpringMVC的父子容器关系
容器 在Spring整体框架的核心概念中,容器是核心思想 就是用来管理Bean的整个生命周期的 在一个项目中,容器不一定只有一个 Spring中可以包括多个容器,而且,容器有上下层关系 一个项目中引入 ...
- spring的父子容器
在创建ssm项目工程时,经常需要读取properties资源配置文件,传统的方法当然可以. 但是spring提供了更简便的方法,@value注解. 在page.properties文件中,配置分页信息 ...
- Spring MVC上下文父子容器
2019独角兽企业重金招聘Python工程师标准>>> Spring MVC上下文父子容器 博客分类: java spring 在Spring MVC的启动依赖Spring框架,有时 ...
- Spring-SpringMVC父子容器
转载自 Spring-SpringMVC父子容器 前言 Spring&SpringMVC作为bean管理容器和MVC默认框架,是大多数web应用都会选择的方案.在其使用过程中,尽管基于xml ...
最新文章
- Docker容器的导出和导入
- BZOJ 1800: [Ahoi2009]fly 飞行棋( 枚举 )
- Office基础和计算机操作基础的知识点(一)
- 第三周总结 类、对象、包
- HDOJ2035 人见人爱A^B
- 从网络读取数据并动态的显示在ListView中
- python函数介绍
- linux sleeping进程多_你知道Linux进程的睡眠和唤醒操作?
- php kindeditor远程图片上传,kindeditor 远程图片本地化,远程图片下载到本地自动更换图片路径...
- 电脑照片太大怎么压缩?照片怎么缩小kb?
- C语言猜数字游戏(超级详解)
- c语言生成excel文件简书,iOS 生成Excel xlsx文件
- 【BZOJ-4316】小C的独立集 仙人掌DP + 最大独立集
- 视频剪辑必备,5个视频素材网站,马住
- 年底打新将空前白热化:闭眼赚钱谁会放过?
- 基础算法一一股神问题
- 泰坦尼克号生存分析(新手入门)
- 微信录音amr音频文件转mp3格式
- 专访星陀资本合伙人秦毅:秉持理性投资之道,着眼于技术应用层
- 精度更高,视野更大的Photoneo3D相机