前言

获取一个bean时AbstractBeanFactory#doGetBean,除非bean已经存在,否则会通过beanDefinition自动创建

创建时,如果没有beanDefinition就会报错,所以beanDefinition是一个很重要的存在

创建流程很复杂,必须要先了解bean的各种后置处理器BeanPostProcessor

spring获取bean时,底层是通过beanName获取的,如果是根据类型,那么他会先根据类型先获取name,然后根据name在获取bean

beanName可以自定义,如果非自定义默认则是classSimpleName,且第一个字母小写
FactoryBean类型的beanName也是同上,如果要获取FactoryBean类型的实例话,则beanName要以"&"为前缀。否则获取的就是factoryBean对应的实际bean

以下为获取(创建)bean的大体流程


通过class类型或注解类型获取beanName

不管怎样,spring底层是通过name获取对应的bean
如果是根据注解获取bean,底层则会遍历所有的beanNames,通过beanNames获取到对应的class,然后然后判断class上是否有相对应的注解
那么咱们只需要关注如何根据beanName获取到对应class,以及如何根据class获取到对应的beanNames就行


通过beanName获取class流程

  1. 从已初始化的单例beansingletonObjects中获取(不允许早期初始化-非循环依赖的方式获取),没有就返回null,有就用返回实例对应的class

    如果是FactoryBean则使用Factory#getObjectType,否则用obj.getClass()直接返回

  2. 如果上一步未满足,并且本地不包含beanDefinition,则尝试从parentBeanFactory中获取,否则执行下一步

  3. 获取beanDefinition
    如果不包含beanDefinition则就直接报错
    通过definition优先获取被包装的definitiongetDecoratedDefinition

    因为有可能目标类将要被代理,在创建beanDefinition的时候就做了手脚,比如说ScopedProxyUtils#createScopedProxy:bean的作用域通过代理实现

  4. 获取beanDefinition对应的class
    最后通过SmartInstantiationAwareBeanPostProcessor#predictBeanType返回对应的beanType

  5. 执行factoryBean的转换
    如果参数beanName是以"&"为前缀,代表要获取FactoryBean类型的class,如果上一步获取到的class不是FactoryBean类型,则返回null
    如果参数beanName不是以"&"为前缀,代表要获取真实bean的类型,如果上一步获取到的不是FactoryBean类型,则直接返回,如果是FactoryBean类型,优先根据泛型获取对应的type,如果获取失败则要进行初始化FactoryBean,因为一会要调用Factory#getObjectType来返回真实的类型
    创建流程请参考AbstractAutowireCapableBeanFactory#createBeanInstance(包含构造注入流程),完事会返回一个BeanWrapper,如果factoryBean本身是单例的话则会放入缓存中factoryBeanInstanceCache在获取bean的时候,保证不能有二次初始化


通过class获取对应的beanNames流程

  1. 获取所有已注册的beanDefinitionNames和手动注册的单例beanNames(手动注册的已初始化)
    条件包含:非alias、非abstract、且是否包含非单例、是否允许早期初始化两个动态条件

  2. 依次遍历beanName

  3. 通过beanName获取class
    与'通过beanName获取class流程'大体流程一致,但是有些许的不同,比如没有beanDefinition不会报错,如果是FactoryBean则尽量不初始化的情况下获取到对应的targetType,否则只能初始化并调用getTargetType

  4. 判断获取到的class

    • 如果没有获取到class则为false,代表不匹配
    • 获取到class之后调用isInstance
      如果返回true则会把当前的beanName添加到list里面,最后一并返回
      如果为false,并且当前的beanName的类型为FactoryBean类型则会拼接'&'前缀作为beanName从新判断

根据beanName优先获取单列的bean


把beanName转换为为标准的beanName

  1. 去除"&"的前缀
    FactoryBean他就是一个普通的bean,在注册beanDefinition时和普通的bean别无二致,只有在获取的时候会有不同
  2. 通过alias获取真实的Name
    alisa其底层实现其实就是一个map,key为alias,value为实际的beanName

优先获取单列,如果非单例的bean压根就获取不到,所以优先获取单列

也可以手动注册单例,但是一样的beanName不允许二次注册(there is already)
手动注册的和spring扫描的且已初始化的单列bean都是存放在同一个地方中:singletonObjects


单例bean的获取流程

  1. singletonObjects优先获取单例bean(手动注册的和spring已初始化的都在同一个地方),有则直接返回

  2. 没有则判断当前的beanName是否为正在创建的单例bean,因为正在创建的bean可能会依赖其他的bean,而其他的bean依赖于正在创建的bean,就变成了一个循环依赖

    spring在每创建一个单例bean之前把当前beanName存放在一个set中,标志正在创建中,创建完之后会从Set删除,并把创建的实例放入到singletonObjects

  3. 如果当前获取的bean正在创建(循环依赖),则会从earlySingletonObjects中获取

    earlySingletonObjects是map类型,作用是暂时存放正在创建的bean,key为beanName,value为bean的实例且是由singletonFactories提供的

  4. 如果earlySingletonObjects获取为空,且允许早期的引用(循环依赖)则从singletonFactories中获取
    singletonFactoriesSmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference提供早期的引用,如aop返回代理对象的引用

    等实例创建完之后会放入到singletonObjects中,并从earlySingletonObjectssingletonFactories移除

  5. 执行factoryBean的转换

其实单例bean获取的时候就已经解决了循环依赖,以上的各个变量就是网上说的三级缓存,如果还不太理解可以直观的看下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
...
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);// 一级缓存,所有已初始化完的单例bean都在这里
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 当前bean正在创建中
singletonObject = this.earlySingletonObjects.get(beanName);// 二级缓存,第一次访问肯定是空的,二级缓存的值由三级缓存提供
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) { // 上锁
singletonObject = this.singletonObjects.get(beanName); // 再次查看一级缓存
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName); // 再次查看二级缓存
if (singletonObject == null) {
// 调用三级缓存,三级缓存是在bean创建的时候放进去的,并且value为ObjectFactory,只有在需要的时候才会初始化
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);// 放入二级缓存中
this.singletonFactories.remove(beanName); // 最后要移除三级缓存
}
}
}
}
}
}
return singletonObject;
}
...
}

factoryBean的转换

如果第一步beanName参数是以"&"为前缀,则必须要返回FactoryBean,获取的不是FactoryBean类型的话直接报错
如果不是"&"前缀,并且获取到的实例为FactoryBean的类型的话,则标记beanDefinition.isFactoryBean=true,并调用FactoryBean#getObject方法返回真正的对象


工厂bean调用方法factoryBean#getObject流程

  1. 首先判断是不是isSingleton,如果不是则直接调用getObject方法并调用BeanPostProcessor#postProcessAfterInitialization此时bean已创建完成(并不会自动装配)
  2. 如果是singletonFactoryBean#isSingleton,则会放入缓存,每次优先取缓存,有则直接返回
  3. 没有缓存则调用getObject,把当前beanName存放在一个set中,标志正在创建中,然后调用BeanPostProcessor#postProcessAfterInitialization此时bean已创建完成(并不会自动装配),完事放入缓存中,并从set中移除

    如果在postProcessAfterInitialization期间又引用了当前的bean的话,则会重新调用getObject返回一个新的对象


获取不到bean则创建

spring对非单例的循环引用会直接报错throw new BeanCurrentlyInCreationException(beanName)

非单例的bean创建之前都会把beanName放入prototypesCurrentlyInCreation中,创建过程中如果存在一样的bean名称,视为循环引用,直接报错,没有循环引用最后创建完则从中移除

创建bean,必须需要beanDefinition,没有则throw new NoSuchBeanDefinitionException

beanDefinition的注册
beanFactory初始化时,通过调用ConfigurationClassPostProcessor向beanFactory中注册符合条件的beanDefinition


创建bean时的前期流程

  1. 如果parentBeanFactory不为空,且当前的beanFactory不包含beanDefinition则交由parentBeanFactory处理,从头开始

  2. 把当前的bean标记为已创建,存放在alreadyCreated中,如果alreadyCreated不为空,代表beanFactory已开始创建bean

  3. 把当前的beanDefinition转换成RootBeanDefinition,root是spring创建bean时的视图,包含了父类的信息,算是一个标准,没有他可不行

    获取rootBeanDefinition逻辑时,如果包含内嵌的类,并且内嵌的类非singleton,则外围类的scope同内嵌的类

  4. 确保dependsOn的beanName优先初始化

    @DependsOn注解或其他配置等

  5. 判断bean的作用域
    首先判断作用域,非单例的其他作用域则在创建前会把beanName放入prototypesCurrentlyInCreation
    如果有循环引用直接报错(通过prototypesCurrentlyInCreation判断是否包含bean的名称),单例的循环引用不报错,最后创建完则从中移除

    自定义的作用域(非单例,非prototype),都会从scopes中取对应的scope实现,比如servlet实现的session、request


通过RootBeanDefinition获取真实的class

如果是FactoryMethod则会通过反射获取方法上返回的类型
如果存在tempClassLoader,则用tempClassLoader加载class,不管用什么,都不会初始化class,除非已经初始化过


通过InstantiationAwareBeanPostProcessor提前实例化

此类为BeanPostProcessor的子类
可以拦截bean实例化之前(不包含factoryBean#getObject),如果返回不为空,则直接调用BeanPostProcessor的后置方法并直接返回,此时bean已创建完毕(很少用)


创建beanWrapper

beanDefinition为class定义的各种信息,beanWrapper为实例化的包装,包含一个实例的各种信息

通过beanDefinition创建BeanWrapper
要考虑到factoryBean有可能已经初始化过在根据beanName获取class的过程中),所以优先从缓存factoryBeanInstanceCache获取factoryBean对应的beanWrapper,没有则会创建

创建beanWrapper其实就是创建bean的实例,创建流程如下

  1. 在beanDefinition中如果提供instanceSupplier则直接调用并返回
    如我们常用的注解@EnableConfigurationProperties,instanceSupplier就是由他提供实现ConfigurationPropertiesValueObjectBeanDefinition

  2. 在beanDefinition中如果提供FactoryMethodName则需要调用此方法获取实例
    如常用的注解@Bean,该方法如果有参数,则会从从beanDefinition和beanFactory中获取,找不到就报错,最终调用factoryMethod并返回

  3. 在beanDefinition中如果有缓存则直接用缓存实例化-非单例的bean可能会多次实例化
    缓存的是构造方法,有其他步骤给给缓存赋值,如果缓存不为空则直接使用,如果有参数,则会从从beanDefinition和beanFactory中获取

  4. 以上步骤都没有实例化则获取所有的构造方法寻找能够实例化的constructor
    优先使用有@Autowire注解的构造,如果required=true,参数不满足则直接报错,否则尝试用其他的

@Lookup注解的原理就是在此实例化bean的时候创建动态代理,具体可参考CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection


单例的bean放入三级缓存中

如果是单例,则通过SmartInstantiationAwareBeanPostProcessor提供早期的引用,并放入三级缓存singletonFactories
等bean初始化完之后如果三级缓存中的bean也初始化了,说明当前bean有循环引用,则用三级缓存中的bean


自动装配和初始化方法调用-aop和ioc

自动装配、初始化方法调用等都是通过beanPostProcessor来实现的
执行beanPostProcessor第四步后面的流程
至此bean实例化、初始化完毕。如果是单例的bean则会放到singletonObjects中,缓存起来

总结

spring在获取bean的时候如果没有就会自动创建,如果是单例的bean就会缓存起来,非单例的每次根据scope作用域创建
spring最著名的莫非IOC和AOP了,在创建bean的时候通过beanPostProcessor完成IOC和AOP等逻辑