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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 昨天的文章里提到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源码写的真好,对逻辑的拆解细分真的太强了,笔者每隔一段时间看一某一小模块的源码总会有一些新的理解,但是个人能力暂时有限,如果有什么理解不对的地方希望多加指正!感谢!下一个系列是好用的开源软件安利篇。

目录
相关文章
|
1天前
|
缓存 前端开发 Java
【Spring】——SpringBoot项目创建
SpringBoot项目创建,SpringBootApplication启动类,target文件,web服务器,tomcat,访问服务器
|
28天前
|
监控 Java 数据库连接
详解Spring Batch:在Spring Boot中实现高效批处理
详解Spring Batch:在Spring Boot中实现高效批处理
153 12
|
28天前
|
安全 Java 测试技术
详解Spring Profiles:在Spring Boot中实现环境配置管理
详解Spring Profiles:在Spring Boot中实现环境配置管理
79 10
|
25天前
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
83 5
|
1月前
|
监控 IDE Java
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
54 8
|
2月前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
2月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
105 2
|
2月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
236 1
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
186 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
118 62