Spring&SpringBoot源码笔记整理 |Bean的加载流程二

简介: 昨天的文章里提到Bean的加载流程和如何获取bean,今天继续源码解读。还是老规矩,看着Bean加载的时序图进入主题。

微信截图_20220531130221.png

前言

昨天的文章里提到Bean的加载流程和如何获取bean,今天继续源码解读。还是老规矩,看着Bean加载的时序图进入主题。 微信截图_20220531130244.png首先是Bean的创建,调用了ObjectFactory的getObject()方法,方法内部直接return了createBean()的方法。

@1.3.1.1  createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
    RootBeanDefinition mbdToUse = mbd;
    //@1.3.1.1 锁定class 根据设置的class属性后者根据className来解析class,反射
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    // TODO Prepare method overrides. 验证以及准备覆盖方法
    try {
        //@1.3.1.2 
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {}
    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        //@1.3.1.3 返回一个代理来替代真正的实例
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {}
    try {
        //@1.3.1.4重点中的重点 创建Bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {}
    catch (Throwable ex) {}
}
复制代码

大致梳理下这个方法的功能:

1. 根据RootBeanDefinition中的class属性或者beanName解释Class
2. 处理override的属性
3. 初始化前的后置处理器(也是AOP的核心实现)
4. 创建bean的具体逻辑
@1.3.1.2 处理override的属性 mbdToUse.prepareMethodOverrides()

ps: 这里注意哈,版本不一样的话,有一些方法是进行改造过的,所以有时候遇到错误或者难以解决的问题,可以想想是不是版本的问题,我个人因为版本问题也吃了不少的亏。微信截图_20220531130346.png

从上面代码我们可以看到,获取类的重载方法列表,然后遍历,一个一个进行处理。具体处理的是 lookup-method 和 replaced-method 属性,这个步骤解析的配置将会存入 beanDefinition 中的 methodOverrides 属性里,是为了待会实例化做准备。摘抄选自《Spring源码深度解析》

微信截图_20220531130554.png

@1.3.1.3 实例化前的前置处理,注意两个重要点applyBeanPostProcessorsBeforeInstantiation(前置处理)和applyBeanPostProcessorsAfterInitialization(后置处理)

方法是为了在调用doCreateBean()之前的短路操作,如果后置处理成功,将直接返回Bean不在继续执行,这里是AOP的核心逻辑。说到AOP谁都知道,无非就是依赖注入而已,实现热插拔的比如日志,权限等等功能,但是实际上AOP能做的事情很多,后面时间充裕的话也解读一下AOP的源码。言归正传我们继续往下看源码。

@1.3.1.4  doCreateBean() bean的具体创建逻辑

在Spring的源码中,do开头的方法都是真正干活的(了解和使用servlet写代码的童鞋应该也是有这种体会),当然bean的创建也就是在doCreateBean()方法中完成的,下面是源码解析。微信截图_20220531130707.png微信截图_20220531130928.png微信截图_20220531130754.png大致流程梳理:

1.单例需要清除缓存
2.创建Bean的实例,并将BeanDefinition转换为包装类BeanWrapper
3.后处理器修改合并后的 bean 定义:bean 合并后的处理,Autowired 注解正式通过此方  法实现诸如类型的预解析
4.依赖处理
5.属性填充
6.循环依赖检查
7.注册DisposableBean(bean销毁时执行destroy())
8.完成创建并返回

因为这个方法做的事情太多了而且很复杂,这里只挑出重点去解析。

@1.3.1.4.1 创建Bean的实例,类createBeanInstance

微信截图_20220531131234.png微信截图_20220531131159.png大致流程梳理:

1. 判断是否有工厂方法,有的话则直接使用工厂方式创建bean
2. 没有工厂方法使用构造函数去创建,因为一个Class可能有多个构造函数,所以去需要根据  参数去区分具体的哪个构造方法。
3. 工厂和带参构造都不存在的话使用默认的构造函数。

继续下一步

@1.3.1.4.2 循环依赖的处理

Spring是通过在Bean实例化完成之前将ObjectFactory加入单例工厂singletonFactories的之中,@1.1 讲了ObjectFactory 是创建对象时使用的工厂。 在对象实例化时,会判断自己依赖的对象是否已经创建好了,判断的依据是查看依赖对象的 ObjectFactory 是否在单例缓存中,如果没有创建将会先创建依赖的对象,然后将 ObjectFactory 放入单例缓存。这时如果有循环依赖,需要提前对它进行暴露,让依赖方找到并正常实例化。

@1.3.1.4.2  属性的注入,方法populateBean(),这里不多赘述

大致流程梳理:

1.调用 InstantiationAwareBeanPostProcessor 处理器的 postProcessAfterInstantiation 方法,判断控制程序是否继续进行属性填充
2.根据注入类型(byName/byType),提取依赖的 bean,统一存入 PropertyValues 中,但是现在大部分是注解的形式,这俩个方法都不会执行
3. 判断是否需要进行 BeanPostProcessor 和 依赖检查,这一步是重点开始注入bean
4. 将所有解析到的 PropertyValues 中的属性填充至 BeanWrapper 中。
在这个方法中,根据不同的注入类型进行属性填充,然后调用后处理器进行处理,最终将属性应用到 bean 中。方法的内容实在太多,也不细说了,主要说下循环依赖的情况,在第2步根据属性注入的时候,假设A需要注入B,恰巧B也需要注入A,这时候无论是autowireByName/autowireByType还是postProcessPropertyValues最终都会调用getBean方法去创建Bean B。这时候通过 getSingleton()方法获取A在@1.3.1.4.2 放入缓存的ObjectFactory,并且通过getObject方法获取A的bean,这时候解决了循环依赖的问题。
@1.3.1.4.3  初始化bean

微信截图_20220531131121.png这个方法大致流程就是Bean分为俩种一种是FactoryBean,另一种就是普通的Bean,普通的bean会直接返回,FactoryBean会委托给getObjectFromFactoryBean进行获取。 Spring中有BeanFactory和FacotryBean要好好区分下:

1. BeanFactory接口的实现类是容器,也是IOC的基本规范。
2. FacotryBean接口的实现类具体返回什么Bean是有实现类的getObject()返回的决定。

总结:     以上两篇文章结合时序图和源码希望帮助大家对Spring加载Bean的过程有个更深的理解。同时不得不感叹Spring源码写的真好,对逻辑的拆解细分真的太强了,笔者每隔一段时间看一某一小模块的源码总会有一些新的理解,但是个人能力暂时有限,如果有什么理解不对的地方希望多加指正!感谢!下一个系列是好用的开源软件安利篇。

目录
相关文章
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
905 7
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
1319 1
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
794 70
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
999 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
机器学习/深度学习 数据采集 人机交互
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
977 0
|
小程序 Java 关系型数据库
weixin117新闻资讯系统设计+springboot(文档+源码)_kaic
本文介绍了一款基于微信小程序的新闻资讯系统,涵盖其开发全过程。该系统采用Java的SSM框架进行后台管理开发,使用MySQL作为本地数据库,并借助微信开发者工具确保稳定性。管理员可通过个人中心、用户管理等功能模块实现高效管理,而用户则能注册登录并查看新闻与视频内容。系统设计注重可行性分析(技术、经济、操作),强调安全性与数据完整性,界面简洁易用,功能全面,极大提升了信息管理效率及用户体验。关键词包括基于微信小程序的新闻资讯系统、SSM框架和MYSQL数据库。
|
小程序 JavaScript Java
基于SpringBoot的智慧停车场微信小程序源码分享
智慧停车场微信小程序主要包含管理端和小程序端。管理端包括停车场管理,公告信息管理,用户信息管理,预定信息管理,用户反馈管理等功能。小程序端包括登录注册,预约停车位,停车导航,停车缴费,用户信息,车辆信息,钱包充值,意见反馈等功能。
1208 5
基于SpringBoot的智慧停车场微信小程序源码分享
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
453 36
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
1447 2
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
IDE Java 应用服务中间件
spring boot 启动流程
Spring Boot 启动流程简介: 在使用 Spring Boot 之前,启动 Java Web 应用需要配置 Web 容器(如 Tomcat),并将应用打包放入容器目录。而使用 Spring Boot,只需运行 main() 方法即可启动 Web 应用。Spring Boot 的核心启动方法是 SpringApplication.run(),它负责初始化和启动应用上下文。 主要步骤包括: 1. **应用启动计时**:使用 StopWatch 记录启动时间。 2. **打印 Banner**:显示 Spring Boot 的 LOGO。 3. **创建上下文实例**:通过反射创建
962 5