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源码写的真好,对逻辑的拆解细分真的太强了,笔者每隔一段时间看一某一小模块的源码总会有一些新的理解,但是个人能力暂时有限,如果有什么理解不对的地方希望多加指正!感谢!下一个系列是好用的开源软件安利篇。

目录
相关文章
|
16天前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
104 26
|
23天前
|
监控 Java 应用服务中间件
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
42 6
|
1月前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
359 12
|
1月前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
83 8
|
2月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
2月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
4月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
237 1
|
4月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
158 1
|
6月前
|
前端开发 Java 开发者
|
6月前
|
Java Spring
Spring的Bean生命周期中@PostConstruct注解
【8月更文挑战第3天】在Spring框架中,`@PostConstruct`注解标示Bean初始化完成后立即执行的方法。它在依赖注入完成后调用,适用于资源加载、属性设置等初始化操作。若方法中抛出异常,可能影响Bean初始化。与之对应,`@PreDestroy`注解的方法则在Bean销毁前执行,用于资源释放。
186 0