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

目录
相关文章
|
2月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
248 3
|
2月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
432 2
|
3月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
2723 1
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
532 0
|
4月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
787 3
|
9月前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
494 0
|
9月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
360 0
|
9月前
|
消息中间件 Java 微服务
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——发布/订阅消息的生产和消费
本文详细讲解了Spring Boot中ActiveMQ的发布/订阅消息机制,包括消息生产和消费的具体实现方式。生产端通过`sendMessage`方法发送订阅消息,消费端则需配置`application.yml`或自定义工厂以支持topic消息监听。为解决点对点与发布/订阅消息兼容问题,可通过设置`containerFactory`实现两者共存。最后,文章还提供了测试方法及总结,帮助读者掌握ActiveMQ在异步消息处理中的应用。
437 0

热门文章

最新文章