当前位置: 首页 > news >正文

Spring父子容器

问题呈现

一个容器可以存在父容器,比如定义一个 Book 类

public class Book {private String name;private Double price;private Integer id;// set get toString...
}

定义两个 XML 文件,一个是父容器的,一个是子容器的:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><bean class="org.example.demo.Book" id="book" ><property name="id" value="111" /><property name="name" value="刘和广" /><property name="price" value="77d" /></bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><bean class="org.example.demo.Book" id="book" ><property name="id" value="222" /><property name="name" value="刘和广之子" /><property name="price" value="77d" /></bean>
</beans>

现在去加载两个容器,注意必须手动 setConfigLocations,配置文件不能放在 ClassPathXmlApplicationContext 构造方法

当从 child 中查找 bean 的时候,首先去 child 容器中查找,这个容器中如果不存在该 bean,那么就去父容器中查找,父容器中不存在,就去爷爷容器中查找。。。

public class App {public static void main(String[] args) {// 父子容器ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext();parent.setConfigLocations("parent.xml");parent.refresh();ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext();child.setConfigLocations("child.xml");child.setParent(parent);child.refresh();Book book = child.getBean("book", Book.class);System.out.println("book = " + book);}
}

原理分析

要实现父子容器的效果,有一个前提,就是我们的容器本身要支持父子容器,而我们日常开发中最常用的 DefaultListableBeanFactory 这个容器,就是支持父子容器的:
在这里插入图片描述
HierarchicalBeanFactory 接口就表示带有层级关系的父子容器了,实现了该接口,就表示这个容器带有层级关系,即具备父子容器的功能。那么接下来,在 Bean 查找的过程中,首先就在当前容器中查找,如果找不到,就去父容器中查找。

根据类型查找,下面这个 getBean 方法最终会调用到 org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveBean 方法:

Book book = child.getBean( Book.class);
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {//这里就是尝试在当前容器中去查找这个目标 beanNamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);if (namedBean != null) {return namedBean.getBeanInstance();}//如果当前容器中没有找到 Bean,则去查找到父容器,然后去父容器中查找 beanBeanFactory parent = getParentBeanFactory();if (parent instanceof DefaultListableBeanFactory dlfb) {//父容器存在,并且是 DefaultListableBeanFactory 类型的,那么则调用 resolveBean 方法去处理 bean,这其实相当于递归return dlfb.resolveBean(requiredType, args, nonUniqueAsNull);} else if (parent != null) {//父容器不是 DefaultListableBeanFactory 类型,但是父容器又存在,那么尝试调用父容器中的 getBeanProvider 方法去获取 beanObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);if (args != null) {return parentProvider.getObject(args);} else {return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());}}return null;
}

根据名字去查找 bean,最终会来到 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 方法中:

Book book = child.getBean("book", Book.class);
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {...else{// Fail if we're already creating this bean instance:// We're assumably within a circular reference.if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 子容器不存在,去父容器查找BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory abf) {return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);} else if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);} else if (requiredType != null) {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);} else {return (T) parentBeanFactory.getBean(nameToLookup);}}}return adaptBeanInstance(name, beanInstance, requiredType);
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 文心快码 Baidu Comate 前端工程师观点分享:以文心快码 Baidu Comate为例,智能代码助手需要什么(三)
  • 神经重建在自动驾驶模拟中的应用
  • CSS盒子模型(三)
  • 解读“酒过三巡,菜过五味”:三巡是多长时间?五味是哪五味?
  • ProtoBuf简要介绍与快速上手使用(C++版)
  • 回调函数的使用
  • 【STM32】看门狗
  • 【Apache Doris】周FAQ集锦:第 19 期
  • pytest自定义命令行选项
  • ML307R_APP_DEMO_SDK TCP/UDP使用介绍
  • 【vue】编辑器段落对应材料同步滚动交互
  • [底层原理] C/C++获取时间(将时间戳转换为年月日)?
  • springboot jar 配置文件同级目录 启动脚本sh 并添加日志文件,日志文件定时分文件
  • RedisDistributedLock 分布式锁
  • Ubuntu 22.04上稳定安装与配置搜狗输入法详细教程
  • angular2 简述
  • angular组件开发
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • node入门
  • SpiderData 2019年2月13日 DApp数据排行榜
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • webgl (原生)基础入门指南【一】
  • 工作中总结前端开发流程--vue项目
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 怎么把视频里的音乐提取出来
  • FaaS 的简单实践
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • # Redis 入门到精通(一)数据类型(4)
  • (~_~)
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (2024,LoRA,全量微调,低秩,强正则化,缓解遗忘,多样性)LoRA 学习更少,遗忘更少
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第1节 (全局数据、栈和堆)
  • (function(){})()的分步解析
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (强烈推荐)移动端音视频从零到上手(下)
  • (转载)(官方)UE4--图像编程----着色器开发
  • (自用)网络编程
  • . Flume面试题
  • .form文件_SSM框架文件上传篇
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • [100天算法】-实现 strStr()(day 52)
  • [20190416]完善shared latch测试脚本2.txt
  • [autojs]autojs开关按钮的简单使用
  • [bug总结]: Feign调用GET请求找不到请求体实体类
  • [BUUCTF 2018]Online Tool(特详解)