spring的bean的加载,说得通俗一点,就是我们通过spring容器,获取到我们想要的bean,而在这个获取过程,spring 做的事情,就是bean的加载;这里我推荐一篇博客,我是通过这篇博客,解决了我的很多疑问Spring源码解析:Bean的加载流程_spring的bean加载过程_所遇皆惊喜的博客-CSDN博客
1. 同样,我们先自己搭建一个spring环境,调用IOC容器的getBean()方法
进入AbstractBeanFactory中的doGetBean方法
2. doGetBean方法
进入到doGetBean方法后,在这里可以大致分为两步,一步是可以直接从缓存中获取到的bean,另一步是不能从缓存中的bean(这里概述可能不是特别准确,建议真心想了解的读者,下来可以真正的更多的通过相应的书籍进行了解)
2.1 这里先了解直接从缓存中就能获取到的bean
进来之后无论是从缓存中获取Bean还是创建bean,都调用了transformedBeanName(name)方法,
transformedBeanName(name)方法:解析name获取真正的beanName,因为传进来的name,有可能是真正的beanName,也有可能是FactoryBean创建的bean然后对应的name,也有可能是bean的alias(bean的别名),无论是这三则那个也好,对于spring来说,它需要的是beanName
2.2 getSingleton(beanName);
这里尝试从缓存中获取Bean
2.3 getObjectForBeanInstance方法
2.3.1 getObjectForBeanInstance方法
在这个方法里面,大致也分为了两步,一步是对FactoryBean工厂生成的bean进行处理,一步则是对默认规则生成的bean进行处理,在这里spring不对按默认规则生成的bean进行任何处理,直接返回;如果用户想要获取的是FactoryBean创建的工厂bean,则直接在传入的name前加‘&’前缀
2.3.2 getObjectFromFactoryBean方法
2.3.3 doGetObjectFromFactoryBean
以上大致就是spring从缓存中加载bean,最后在调用postProcessObjectFromFactoryBean后处理器
3. 缓存中没有获取到bean
4. 获取单例bean:getSingleton的重载方法
进来之后,spring还是首先尝试从缓存中获取bean,如果确实没有,才来真正的创建bean(spring会把单例bean放入缓存中,提高效率),调用传进来的ObjectFactory的getObject方法,获取bean,ObjectFactory由createBean方法返回,创建bean的过程主要也在createBean方法中
beforeSingletonCreation()方法:记录当前bean为正在创建的bean
bean加载的大致过程就是这样的,接下来我们看一下正在创建bean的过程createBean方法
5. createBean方法:真正创建bean的方法
进入createBean方法
进入到createBean方法后,spring首先通过beanName或则设置的class属性来解析class,然后对bean的override方法进行处理,这里其实是对XML中replace-method和lookup-method进行处理,在spring中,spring就是把这两个属性放在了BeanDefinition中的OverrideMethod属性中,然后在实例化前调用实例化前的前置处理器
进入prepareMethodOverrides()方法
进入prepareMethodOverride方法
在这里我们看到spring获取对应方法名的对应个数,如果获取到对应方法名的个数为1,则说明改方法没有被重载,则直接标识,后续过程中则可以直接拿来用,节约解析开销
进入resolveBeforeInstantiation方法
进入这个方法后,里面主要的逻辑就是调用实例化前的后处理器,和调用实例化后的后处理器,为什么这里要调用实例化后的后处理器,因为在spring中,无论是怎么实例化的bean,spring都尽可能的会调用实例化的后处理器;因为如果返回的bean不为空spring便不会在调用普通bean的实例化过程
然后继续往下走,到doCreateBean方法,经过我们之前对spring源码的观看学习,发现spring大部分正在做实事的都是一do开头的方法,在这里bean的实例化也不例外
6. doCreateBean方法
进入doCreateBean方法后,spring先通过构造器/工厂配置创建BeanWrapper
BeanWrapper:可以看作是偏底层的 bean 包装器,提供了对标准 java bean 的分析和操作方法,包括获取和设置属性值、获取属性描述符,以及属性的读写特性等(可简单理解,这里为spring创建的空壳bean,还没有填充属性,初始化,AOP等后续功能的bean)
判断当前创建的bean是否运行循环依赖,是否是单例的,是否是正在创建的bean,如果都满足,则将当前bean对应的ObjectFactory放入到缓存中(也就是三级缓存),这一步也是为了解决循环依赖(这里放的ObjectFactory可以暂时理解成就是当前bean的空壳bean)
7.当前面的操作做完后,接下来就是spring的属性注入和初始化
8.经过属性注入和初始化后,spring还会对存在循环依赖的bean再次检查当前bean是否还存在循环依赖
如果从缓存中获取到了单例bean,则说明spring经过了循环依赖,如果获取到的单例bean不等于当前正在创建的bean,则说明当前bean还存在循环依赖,或则说当前bean在初始化的时候还做了其它操作(代理增强了当前bean);则spring会直接抛出异常,告诉用户当前Bean还存在循环依赖问题
9.最后在注册DisposableBeanIfNecessary
Spring 中不但提供了对于初始化方法的扩展入口,同样也提供了销毁方法的扩展入口,对 于销毁方法的扩展,除了我们熟知的配置属性 destroy-method方法外,用户还可以注册后处理 器DestructionAwareBeanPostProcessor来统一处理bean的销毁方法
10.另外我们在看一下创建BeanWrapper的方法
createBeanInstance
进入到createBeanInstance方法后,首先先获取Class文件,然后在判断当前bean是否允许被创建,如果当前Bean不被允许创建,则直接报错抛出异常,然后在判断当前创建bean是否满足其对应的工厂规则,如果满足,则直接用其对应的工厂规则创建并返回对应的BeanWrapper对象
如果工厂规则不存在,则利用构造函数创建对应的BeanWrapper,首先解析,确认具体的构造函数,因为一个bean可能存在多个构造函数,其次判断是否已经解析并确认了构造函数,如果已经解析了是有参构造函数,则直接调用对应的构造函数,创建并封装成对应的BeanWrapper对象,否则调用默认的构造函数创建并封装对应的BeanWrapper对象
11.进入默然构造方法创建Bean并封装成BeanWrapper对象
instantiateBean方法
进入到instantiateBean方法后,首先判断当前bean是否有需要覆盖或则替换的方法,如果有则需要通过cglb动态代理,因为可以在创建动态代理的过程中直接将动态方法植入类中,否则直接通过反射创建bean
12.initializeBean方法
进入初始化方法,在执行初始化方法时,spring为用户提供了,多个接口用来让用户对生成的bean做扩展,入Aware回调接口和BeanPostPreccessors接口
总结
spring的bean的加载流程
1.spring 先对name进行解析,得到真正的beanName
2.尝试从缓存中获取bean,如果获取到了,则根据当前bean的规则进一步对当前bean做处理,然后直接返回当前bean
3.没有从缓存中获取到bean,则创建bean,首先检查当前bean是否不是单例的,并且存在循环依赖,如果满足则直接抛出异常,因为spring没有对多例bean存在循环依赖问题做处理
4.然后在通过从BeanDefinition中获取当前bean的所有信息,然后创建bean
5.创建单例bean,调用getSignleton的重载方法
5.1 首先记录当前bean的正在创建的状态,然后调用正在创建bean的方法createBean创建Bean
5.2 进入createBean,首先通过对应bean的创建规则(FactoryBean/构造器规则/默认规则)创建bean对应的BeanWapper对象
5.3 检查当前bean是否符合解决循环依赖的所有条件,如果都满足,则记录从BeanWrapper中获取到的bean对应的ObjectFactory对象放入到三级缓存中
5.4 然后在属性注入
5.5 然后在初始化,在初始化中,首先会经过Aware回调,其次在经过beanPostProcessors的前置处理方法,然后在真正的初始化,然后在经过beanPostProcessors的后置处理方法
5.6 最后在进行循环依赖检查,如果当前Bean还存在循环依赖,则直接报错
5.7 最后注册DisposableBeanIfNecessary
5.8 删除正在创建bean的状态
5.9 加入单例池中
最后笔者建议,真正想知道bean的加载流程的同学,还是去看笔者推荐的那篇文章,那篇文章才是真正对bean的加载流程的详细讲解;这里笔者相当于只是对笔者学习笔记的一个整理,还有很多没有记录,后续笔者在完善加强