热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

spring源码解析(一)bean的生命周期

首先来一张bean的生命周期图该篇文章将以加载类为起点开始分析bean的生命周期。首先不能完全保证理解正确,只是博主自己的思路,有问题及时指出ÿ

首先来一张bean的生命周期图

该篇文章将以加载类为起点开始分析bean的生命周期。首先不能完全保证理解正确,只是博主自己的思路,有问题及时指出,共同进步。

bean生命周期源码分析


加载类

源码将从AbstractAutowireCapableBeanFactory中的createBean方法开始分析,也就是合并完beanDefinition,开始加载类。

@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {...RootBeanDefinition mbdToUse = mbd;// 确保bean类在这一点上得到了实际的解析Class resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.try {mbdToUse.prepareMethodOverrides();}...try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}...try {Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}...}

从以上源码可以看到调用了第一个resolveBeanClass,进入该方法查看。

//是否已经有了beanClass
if (mbd.hasBeanClass()) {return mbd.getBeanClass();
}
//安全管理器
if (System.getSecurityManager() != null) {return AccessController.doPrivileged(new PrivilegedExceptionAction>() {@Overridepublic Class run() throws Exception {return doResolveBeanClass(mbd, typesToMatch);}}, getAccessControlContext());
}
else {//加载类,这里面就是类加载器加载类的逻辑了return doResolveBeanClass(mbd, typesToMatch);
}

实例化前

分析完resolveBeanClass方法后回到createBean方法中来,继续向下走,看这一段代码。

try {//给BeanPostProcessors一个返回代理而不是目标bean实例的机会Object bean = resolveBeforeInstantiation(beanName, mbdToUse);//如果已经返回了对象,则不再执行spring的实例化流程,直接返回beanif (bean != null) {return bean;}
}

resolveBeforeInstantiation方法中有这样两个方法,bean通过InstantiationAwareBeanPostProcessor接口来实现两个影响实例化的方法,允许第三方可以不按照Spring的正常流程来创建一个Bean,利用InstantiationAwareBeanPostProcessor接口的方法来提前返回一个Bean对象,直接结束Bean的生命周期,从而达到干预bean实例化的过程。这就对应上一步 给BeanPostProcessors一个返回代理而不是目标bean实例的机会

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class targetType = determineTargetType(beanName, mbd);if (targetType != null) {bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {
//如果实例化前的时候返回了对象,说明不再使用spring提供的实例化流程,这时直接调用实例化后方法。bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}

一个小demo

当对象是user时,会被实例化前处理器处理,生成一个order对象,然后直接结束bean的生命周期。

@Component
public class MyInstantiation implements InstantiationAwareBeanPostProcessor {//允许第三方可以不按照Spring的正常流程来创建一个Bean,
// 可以利用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法来提前返回一个Bean对象,
// 直接结束Bean的生命周期@Overridepublic Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {System.out.println("被干预的beanName:"+beanName);if (beanName.equals("user")){System.out.println("干预原本的bean的生命周期,生成其他对象实例");return new Order();}return null;}}

推断构造方法和实例化

回到createBean方法中 继续向下走,有这么一句代码。去做创建bean的操作

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

进入doCreateBean方法查看。

BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//在这里去执行了bean的实例化instanceWrapper = createBeanInstance(beanName, mbd, args);}//原始对象final Object bean = instanceWrapper.getWrappedInstance();//原始对象的class类型Class beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}

createBeanInstance方法中进行了构造方法的推断以及实例化,作为单独篇章分析:https://blog.csdn.net/qq_39404258/article/details/109769278

beanDefinition的后置处理

在doCreateBean方法中继续走,到这里进行beanDefinition的后置处理

// 允许后处理程序修改合并的bean定义。
synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {//在这里可以添加修改beanDefinition的内容,可以算作一个beanPostProcessor的扩展点applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}
}

这里执行了applyMergedBeanDefinitionPostProcessors方法,原理都是beanPostProcessor。自定义beanPostProcessor通过实现MergedBeanDefinitionPostProcessor接口内的相应方法即可。

在doCreateBean方法中继续走,在这里进行了循环依赖的逻辑,作为单独篇章分析:https://blog.csdn.net/qq_39404258/article/details/108367587

// 如果当前创建的是单例bean,并且允许循环依赖,并且还在创建过程中,那么则提早暴露boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// 此时的bean还没有完成属性注入,是一个非常简单的对象// 构造一个对象工厂添加到singletonFactories中,getEarlyBeanReference暂时没断点到,疑似lambda的问题addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }// 该bean就是实例化对象
Object exposedObject = bean;

至此,已经获取到了实例化对象,接下来讲实例化对象进行属性填充。

实例化后

这时我们还在doCreateBean方法,下面这个方法是属性填充方法

populateBean(beanName, mbd, instanceWrapper);

进入这个方法,略过判空,看这段循环。只有postProcessAfterInstantiation返回值是false才会进行属性填充,否则直接结束属性填充。

// 在设置属性之前,给任何instantiationwarebeanpostprocessors机会修改bean的状态。
// 我们可以自己写一个InstantiationAwareBeanPostProcessor,然后重写postProcessAfterInstantiation(实例化后)方法来判断是否进行属性填充,
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// 如果该方法返回false,那么则不会进行属性填充了,直接return了if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}
}

属性填充

接着向下走是进行属性填充(依赖注入),作为一个单独的篇章进行分析。

@autowired源码注入分析https://blog.csdn.net/qq_39404258/article/details/109472260

aware回调

结束属性填充,回到doCreateBean方法继续走。

//暴露这个对象
exposedObject = initializeBean(beanName, exposedObject, mbd);

然后进入initializeBean方法查看。

//安全处理器,没有忽略
if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());
}
else {//调用aware回调invokeAwareMethods(beanName, bean);
}

初始化

在这个initializeBean方法内继续向下走,执行初始化前、初始化、初始化后方法。

Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {
//执行postProcessBeforeInitialization() 方法(初始化前)wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//执行初始化方法init,需实现InitializingBean接口invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {
//执行postProcessAfterInitialization() 方法(初始化后)wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}

销毁注册

再回到doCreateBean方法,最后面有一个这样的方法registerDisposableBeanIfNecessary,用于将实现了DisposableBean接口的bean注册进去用于close时的销毁。

registerDisposableBeanIfNecessary(beanName, bean, mbd);

以上为bean的部分生命周期::(加载类)-> 实例化->(填充属性)->(aware回调)->初始化。

总结一下在bean的生命周期里需要使用到的接口以及扩展的beanPostProcessor

1.加载类

2.实例化前  InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

3.实例化 暂时没有分析

插入了一个beanDefinition后置处理器  MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition

4.实例化后 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation

5.填充属性 InstantiationAwareBeanPostProcessor.postProcessProperties

6.aware回调

7.初始化前 BeanPostProcessor.postProcessBeforeInitialization

8.初始化 InitializingBean.afterPropertiesSet,当然不止这一种可以初始化,注解(@PostConstruct)和xml(init-method)方式都可以

9.初始化后 BeanPostProcessor.postProcessAfterInitialization

10.bean使用中

11.bean销毁 DisposableBean.destroy,当然不止这一种可以销毁,注解(@PreDestroy)和xml(destroy-method)方式都可以


推荐阅读
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
  • Spring框架中枚举参数的正确使用方法与技巧
    本文详细阐述了在Spring Boot框架中正确使用枚举参数的方法与技巧,旨在帮助开发者更高效地掌握和应用枚举类型的数据传递,适合对Spring Boot感兴趣的读者深入学习。 ... [详细]
  • 在List和Set集合中存储Object类型的数据元素 ... [详细]
  • 本文深入解析了WCF Binding模型中的绑定元素,详细介绍了信道、信道管理器、信道监听器和信道工厂的概念与作用。从对象创建的角度来看,信道管理器负责信道的生成。具体而言,客户端的信道通过信道工厂进行实例化,而服务端则通过信道监听器来接收请求。文章还探讨了这些组件之间的交互机制及其在WCF通信中的重要性。 ... [详细]
  • ### 优化后的摘要本学习指南旨在帮助读者全面掌握 Bootstrap 前端框架的核心知识点与实战技巧。内容涵盖基础入门、核心功能和高级应用。第一章通过一个简单的“Hello World”示例,介绍 Bootstrap 的基本用法和快速上手方法。第二章深入探讨 Bootstrap 与 JSP 集成的细节,揭示两者结合的优势和应用场景。第三章则进一步讲解 Bootstrap 的高级特性,如响应式设计和组件定制,为开发者提供全方位的技术支持。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • Squaretest:自动生成功能测试代码的高效插件
    本文将介绍一款名为Squaretest的高效插件,该工具能够自动生成功能测试代码。使用这款插件的主要原因是公司近期加强了代码质量的管控,对各项目进行了严格的单元测试评估。Squaretest不仅提高了测试代码的生成效率,还显著提升了代码的质量和可靠性。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 在使用 SQL Server 时,连接故障是用户最常见的问题之一。通常,连接 SQL Server 的方法有两种:一种是通过 SQL Server 自带的客户端工具,例如 SQL Server Management Studio;另一种是通过第三方应用程序或开发工具进行连接。本文将详细分析导致连接故障的常见原因,并提供相应的解决策略,帮助用户有效排除连接问题。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 本文探讨了 Java 中 Pair 类的历史与现状。虽然 Java 标准库中没有内置的 Pair 类,但社区和第三方库提供了多种实现方式,如 Apache Commons 的 Pair 类和 JavaFX 的 javafx.util.Pair 类。这些实现为需要处理成对数据的开发者提供了便利。此外,文章还讨论了为何标准库未包含 Pair 类的原因,以及在现代 Java 开发中使用 Pair 类的最佳实践。 ... [详细]
author-avatar
逗趣游戏
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有