BeanDefinitionReader接口,Spring加载Bean的过程(非常流畅和容易理解)(Spring源码分析1)

一、前言

        前言部分,介绍Spring框架的工作和大致原理,有基础的小伙伴可以跳过

        我们现在最常使用的开发框架SSM,分别是Spring、Spring MVC和Mybatis,其功能已经超出原生Spring非常多,所以想学习Spring原理,首先要走到底层。

        第一,Spring框架,最关键的功能是bean的管理。

        bean,可以理解成一个实例化的实体对象,使用过Spring的都知道,我们配置XML文件或者注解开发时,需要配置一个bean属性【在注解中,则是使用@Component注解】

        这个配置的目的,就是告诉Spring某些信息。

        最重要也是最基础的两个,一个是bean指向的类,另一个是bean的名称。

        当然,还有单例或原型、初始化方法、销毁方法等等。

        不过所有的这些信息,都指向BeanDefinition

        BeanDefinition,就是Spring对bean的定义,我们要使用bean,绕不开这个接口。

        第二,Spring的核心设计,在于如何用配置文件,管理Bean

        学习过设计模式的同学,应该对“工厂模式”有所了解,在此不介绍基础原理。

        我们只需记住,Spring中,工厂是用BeanFactory接口体现的

        不过我们常用的工厂方法,很明显有一个缺点:对于接口Data,它每增加一个实现类,就要配置相关信息。

        这也是Spring的问题所在,所以我们一旦增加一个类,就要用@Component注解该类。

        我们考虑一个问题:明明只有配置文件,为何Spring框架却能将XML文件中的Bean定义,实例化出来呢?

        记住下面的流程

        第一步,必须把Bean信息读取出来,也就是说,要有读取XML文件的能力。

        第二步,Spring框架必须能实例化这个Bean,并且要有至少一个容器【数据结构】,来存储这些实例对象。

        第三步,Spring至少对外有一个接口,使外界可以得到这个Bean。

二、从代码入手,学习底层的Spring使用方法【下面会统一说明这些名词】     

        我们考虑下面这行代码,现在已经很少有人这么写了,不过为了学习Spring的原理,我们必须先把Spring的Context部分放在一旁,专注于beans这个核心部分。

    public static void main(String[] args) throws Exception{// 建造Spring工厂DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 初始化读取器。XmlBeanDefinitionReader beanDefinitionReader =new XmlBeanDefinitionReader(beanFactory);// 调用 加载 方法。【注:虽然是叫“加载”方法,但事实上完成了加载、注册和实例化功能】beanDefinitionReader.loadBeanDefinitions("Spring.xml");MyService myService = (MyService) beanFactory.getBean("myService");myService.serve(); // 只有一个打印方法}

        这段代码做了什么事呢?

        按流程来说,请保持疑问。

        第一,new一个BeanFactory工厂

                疑问1:为什么使用Default Listable Bean Factory,而不是使用BeanFactory作为声明?

                疑问2:为什么这个对象的new,不需要参数?那把它new出来有什么用处?

        第二,new一个BeanDefinitionReader读取器

                疑问1:Xml BeanDefinitionReader和我说的BeanDefinitionReader有什么关系?

                疑问2:将这个BeanFactory传递进去,会发生什么?为什么需要这个Factory?

        第三,调用读取器reader的load方法

                疑问1:这个方法做了什么?为什么一下子就能使用Bean了?

三、记住几个重点名词

        首先,我要说一下几个重点名词,以及它的含义。

        记住:loadBeanDefinitions方法、Resource接口、resourceLoader属性。

        按照类来解释。

        BeanDefinition

                Bean的定义,这个我想大家都了解,不过请记住一点:BeanDefinition是Spring的唯一数据类,这个类定义了所有数据,其它类定义的数据,都是为了辅助这个类的使用。

        BeanFactory

                工厂类,但不负责加载、初始化Bean,这个接口的唯一作用,其实是管理Bean【比如在外界需要时,传递一个bean对象】

                这个接口的下层实现接口非常多,比如ListableBeanFactory,在此不介绍。

                最重要的一个实现类,即DefaultListableBeanFactory,这个类同时实现了另一条支线上的BeanDefinitionRegistry接口。

                这个实现类,有一个HashMap的数据结构beanDefinitionMap,存储了所有的bean,无论是bean的注册还是初始化,都要使用到它。

                这就相当于生出了一个同时拥有二者能力的儿子。

        BeanDefinitionRegistry

                一个拥有注册Bean能力的接口,并非本文重点。

                不过在Bean加载结束后,注册就要依靠它。

        BeanDefinitionReader

                这是本文的重点之一,这个接口的类继承结构如下图所示。

                我们忽略Groovy、Properties,因为它们不是很重要。

                Reader接口只定义了一些方法,在此不赘叙。

                在Abstract中,实现了通用的方法,其中最重要的就是loadBeanDefinitions方法,这个方法的重载很多,实际的加载过程,甚至放在子类中实现。

                不过不影响它的重要性,因为它将资源文件,全部转化为Resource资源,以便可以统一地访问数据。

                至此,介绍完毕。

四、加载Bean,Spring的初始工作

        有了前文的基础,这一步就轻松很多,让我们来看看源码。

        我必须解释一下,BeanDefinitionReader读取器,它的new需要一个factory的原因,是它在加载方法中,调用了Bean注册、初始化的方法。

        如果单纯的“加载”资源,使其成为可读的Document格式,不需要一个factory。【当然,实际上这个factory在reader眼里,是一个rigistry注册器】

        第一步,走进Abstract抽象类loadBeanDefinitions方法里【参数:String location】

                为了使代码结构更清晰,我把异常处理、日志记录都删除了,以下是我的分析。【忽略如何拿到加载器、以及如何加载资源】

                我再次强调一下,Resource类,是Spring对底层资源的统一访问接口,所以拿到Resource对象是第一步。

                首先,拿到资源加载器。

                然后,根据加载器的类型【一次读取n个资源,或者1个资源】,拿到资源。

                最后,把资源放入集合,等待处理。

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources){ResourceLoader resourceLoader = this.getResourceLoader();  int count;// 加载一个或多个资源if (resourceLoader instanceof ResourcePatternResolver) {// 多资源加载器,一次加载多个资源Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);count = this.loadBeanDefinitions(resources);if (actualResources != null) {// 将资源类Resource,放进集合Collections.addAll(actualResources, resources);}return count;    }} else {// 单资源加载器,一次加载一个资源Resource resource = resourceLoader.getResource(location);count = this.loadBeanDefinitions((Resource)resource);if (actualResources != null) {actualResources.add(resource);}return count;}}}

        第二步,走进Xml子类实现的loadBeanDefinitions方法中【参数:Resource resource】

                这一步骤里,我依旧删除了异常处理、日志和一些语句,保留了比较重要的方法。

                EncodedResource相当于Resource的编码结果,与Resource差别不大,在此忽略。

                主要做了两件事

                第一,将资源转化为InputSource。

                第二,调用doLoadBeanDefinitions方法。【真正的加载bean方法】

public int loadBeanDefinitions(EncodedResource encodedResource){Assert.notNull(encodedResource, "EncodedResource must not be null");Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();int var6;InputStream inputStream = encodedResource.getResource().getInputStream();Throwable var4 = null;// 将资源转化为InputSourceInputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 最重要的一步var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());return var6;
}

        第三步,走进doLoadBeanDefinitions方法

                这一步的主要逻辑,就是得到Document文件,然后调用registerBeanDefinitions方法。

Document doc = this.doLoadDocument(inputSource, resource);
int count = this.registerBeanDefinitions(doc, resource);return count;

        至此,Bean的加载已经完毕,Document类,已经可以支持Spring注册bean和实例化bean,从底层XML资源,转化为可读的资源,已经完成。

        至于Resource、Document是什么,ResourceLoader的原理又是什么,这部分我在下次再写。

五、结语

以上就是我分享的对Spring框架的理解。

         我是蚊子码农,如有补充或者疑问,欢迎在评论区留言。个人的知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

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

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

相关文章

大漠插件7.2422

工具名称:大漠插件7.2422 /更新时间2024年6月2日 / v7.2422 1. 综合工具的图像编辑工具可以缩放窗口了 2. 增加AiFindPic AiFindPicEx AiFindPicMem AiFindPicMemEx AiEnableFindPicWindow 共5个接口 / 工具简介: 大漠 综合 插件 (dm.dll)采用vc6.0编写&#xff0c;识别速度超级…

Java 初识

Java 的发展历程 Sun 公司。 Oracle 公司。 普通版本&#xff0c;也叫过渡版本。 正式版本&#xff0c;也叫长期支持版本&#xff08;LTS&#xff09;。 Java SE&#xff0c;Java EE&#xff0c;Java ME Java 技术体系分为三个平台&#xff1a;Java SE&#xff0c;Java EE&a…

EasyExcel导出多个sheet封装

导出多个sheet 在需求中&#xff0c;会有需要导出多种sheet的情况&#xff0c;那么这里使用easyexcel进行整合 步骤 1、导入依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><d…

多尺度注意力创新

深度之眼17种多尺度注意力创新

西门子PLC学习之数据块的单个实例,多重实例与参数实例间的区别

首先介绍下函数&#xff0c;函数块与数据块这三个概念。 数据块 数据块里可以存储各种类型的参数。有人可能会问&#xff0c;m寄存器不是可以存储布尔值&#xff0c;8位&#xff0c;16位&#xff0c;32位变量吗&#xff0c;为什么要多此一举&#xff1f;因为虽然m寄存器能存储以…

​​​​​​​月薪20K的程序员应具备怎样的技能和水平?

在当今互联网高速发展的时代&#xff0c;程序员的薪资水平也在不断提高。对于月薪20K的程序员来说&#xff0c;他们不仅需要具备扎实的编程基础&#xff0c;还需要掌握一系列与工作相关的技能和能力。 月薪20K的程序员应具备怎样的技能和水平&#xff1f; 相信这是一个很多人都…

什么是智慧零售?智慧零售的发展前景如何?

在零售业的快速发展中&#xff0c;市场竞争日益激烈&#xff0c;产品同质化严重&#xff0c;线下销售与线上商店的竞争加剧&#xff0c;资金成本问题日益凸显。这些问题不仅限制了零售业的发展&#xff0c;也给消费者带来了诸多不便。然而&#xff0c;智慧零售的出现&#xff0…

ElementUI中date-picker组件,怎么把大写月份改为阿拉伯数字月份(例如:一月、二月,改为1月、2月)

要将 Element UI 的 <el-date-picker> 组件中的月份名称从中文大写&#xff08;如 "一月", "二月"&#xff09;更改为阿拉伯数字&#xff08;如 "1月", "2月"&#xff09;&#xff0c;需要进行一些定制化处理。可以通过国际化&a…

45-5 护网溯源 - 远控木马样本溯源

在分析恶意样本时&#xff0c;需要查看包括作者名字、ID、IP地址、域名等在内的相关信息。 把恶意样本上传到微步、360沙箱云分析&#xff1a;样本报告-微步在线云沙箱 (threatbook.com) 动态分析 运行截图 发现该木马是与一个装机软件绑定的&#xff0c;你运行正常软件的时候…

封装组件库仿elementui<1>

目录 type属性 引入字体图标 button的点击事件 disabled属性 methods:{//点击事件是外部注册的handleClick(e){this.$emit(click,e)//通知父组件点击了&#xff0c;点了按钮&#xff0c;触发外界的click&#xff1f;传参为事件对象//向父组件派发了click事件} }, type属性…

项目进度管理必备:15款最佳项目进度跟踪工具推荐

15好用的款主流项目进度管理软件&#xff1a;PingCode、Worktile、Trello、Tower、Asana、Smartsheet、Teambition、ClickUp、Wrike、Monday.com、Notion、禅道、飞书、云效、蓝凌。 严格的进度管理有助于更好地控制项目进展&#xff0c;提升团队效率&#xff0c;最终实现项目成…

减调食谱攻略:美味低卡又健康

早餐主要求质&#xff0c;也就是求营养&#xff0c;更确切的说是“均衡的营养&#xff0c;多重的营养元素”确保每天早餐不重样就差不多了。 早餐主食&#xff1a;蛋羹、糖心水煮蛋&#xff0c;皮蛋瘦肉粥、南瓜粥、小米粥&#xff0c;蒸煮玉米、南瓜、芋头、红薯&#xff0c;…

【Linux】The server quit without updating PID file的几种解决方案

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

Java使用XWPFTemplate将word填充数据,并转pdf

poi-tl poi-tl&#xff08;poi template language&#xff09;是基于Apache POI的Word模板引擎。纯Java组件&#xff0c;跨平台&#xff0c;代码短小精悍&#xff0c;通过插件机制使其具有高度扩展性。 主要处理区域有这么几个模块: 依赖 <dependency><groupId>…

记忆++入门01

1.数字编码 2. 地点桩 1. 卧室 2.婴儿房 3.卫生间 4.次卧 5.书房 6.厨房 7.餐厅 8.客厅 9.阳台左 10.阳台右

深度学习每周学习总结P10(车牌识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 数据链接 提取码&#xff1a;ppv1 –来自百度网盘超级会员V5的分享 目录 0. 总结1. 数据导入、查看数据分类&#xff0c;自定义transform…

【TB作品】MSP430G2553单片机,MSP430 单片机读取 SHT30 传感器并显示数据

使用 MSP430 单片机读取 SHT30 传感器并显示数据 作品功能 本文介绍了如何使用 MSP430 单片机读取 SHT30 温湿度传感器的数据&#xff0c;并通过 OLED 屏幕显示实时的温度和湿度信息。通过此项目&#xff0c;您将学习如何配置 MSP430 的 I2C 接口、读取 SHT30 传感器的数据以…

高考志愿填报有哪些技巧和方法

一年一度高考季&#xff0c;又高考志愿填报的时侯了。高考志愿填报的时侯&#xff0c;需要考虑的因素比较多&#xff0c;有的同学觉是离家越远越好&#xff0c;要放飞自我&#xff0c;家长再也管不了我了。有的同学觉得专业比学校牌子重要&#xff0c;只要报个好专业&#xff0…

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:大型机械智能预警系统

三一重工股份有限公司&#xff0c;是由三一集团创建于1994年&#xff0c;通过打破国人传统的“技术恐惧症”坚持自主创新迅速崛起。2011年7月&#xff0c;三一重工以215.84亿美元的市值荣登英国《金融时报》全球市值500强&#xff0c;是迄今唯一上榜的中国机械企业。2012年1月&…

AI和机器人引领新一轮农业革命

AI和机器人技术在农业领域的应用正在迅速发展&#xff0c;未来它们可能会实现厘米级精度的自主耕作。 精确种植&#xff1a;AI算法可以分析土壤条件、气候数据和作物生长周期&#xff0c;以决定最佳种植地点和时间。 土壤管理&#xff1a;利用传感器和机器学习&#xff0c;机器…