spring的Bean创建以及初始化流程

2,633 阅读4分钟

概述

我们首先来看一下spring的大体架构图 image.png

BeanDefinition信息注册到BeanDefinitionRegistry流程

BeanDefinition在Spring中被设计为一个Bean的定义信息,其中包含是否懒加载,是否有依赖其他的Bean,是否单例等等,这些属性spring抽象出了一个类BeanDefinitionRegistry来进行管理,该类提供对BeanDefinition的增删改查功能。那我们现在来看看spring是如何用BeanDefinitionRegistry来管理BeanDefinition的

public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestApp.class);
        Cat bean = context.getBean(Cat.class);
        System.out.println(bean);
}

Spring注册BeanDefinition的工具类

我们首先需要记住的一个最核心的点是:注册BeanDefinition到Registry是使用一个工具类的方法 image.png 在方法中其实就是调用了registry的注册方法 image.png 容器内部其实就是用一个map来保存映射关系 image.png

工具类在Spring中的注册过程

我们上面已经知道了Spring是通过一个工具类来注册,注册的本质其实也是把Bean的名称和定义信息存储在了一个map里面,那么我们现在就来看看spring是在什么时候把bean的定义信息存储到map里面去的。

  1. spring容器初始化之前先调用了一个初始化的方法,方法内部直接先写死注册了几个对象 image.png 注意看上图注册了一个ConfigurationClassPostProcessor image.png
  2. 在refresh方法中,执行容器中所有BeanFactoryPostProcessor的方法,其中就包含刚才硬编码进来的ConfigurationClassPostProcessor类,在该类中遍历所有的配置类然后调用自己的一个parser去解析每个配置找到这些配置包含的Bean并注册到容器中 image.png image.png

小总结

这里需要知道spring有一个 BeanFactoryPostProcessor的生命周期接口,然后在初始化的时候会硬编码加载一个ConfigurationClassPostProcessor的对象,在refresh方法中会调用该方法的接口,在接口中就会扫描所有配置类然后去加载对应的bean到容器中。注意这里只是加载定义信息,并没有真正的初始化对象。

创建单实例Bean流程

我们刚才看的是Bean的定义信息已经被保存到spring中,我们现在来看看Spring创建实体对象的流程。

  1. DefaultListableBeanFactorypreInstantiateSingletons方法中,遍历所有之前注册的BeanDefinition然后挨个初始化

image.png

2 spring让用户可以自定义创建bean到容器中,如果没有则spring自己创建,如果用户自己实现了InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法就可以自己返回bean image.png 3. spring自己创建bean的流程会判断需不需要动态代理来不同方式创建bean(大概) image.png

Bean创建对象总结

image.png

Bean属性赋值过程

在一开始我们看spring容器初始化的时候有看到硬编码注册了几个组件,其中还包括了AutowiredAnnotationBeanPostProcessor类,该类是用来做spring属性赋值的,该类也属于Bean后置处理器。

  1. 创建好bean之后调用populateBean来给bean属性赋值 image.png
  2. 获得bean的后置处理器找到InstantiationAwareBeanPostProcessor 对象调用方法 image.png
  3. 刚才注册的AutowiredAnnotationBeanPostProcessor就是属于该类,在方法中会找到每个类中的属性是否包含@Autowired,或者@Value 注解的属性,有就生成一个Metadata然后调用set方法 image.png

自定义赋值流程

在知道了spring是如何自动注入属性之后,我们还可以自定义给bean的属性赋值,还是看populateBean方法 image.png 在spring提供的后置处理器完成spring属性赋值之后,spring还提供了让用户可以自己给属性赋值的方式 image.png 如图只需要自定义InstantiationAwareBeanPostProcessor,然后返回一个PropertyValuesspring就会自动给对象的属性赋值,内部也是invoke set方法。

属性赋值总结

spring在一开始的时候硬编码注入的组件AutowiredAnnotationBeanPostProcessor在初始化bean后开始寻找bean中属性上写了@Autowired和@value注解,然后注入对应的值,用户也可以实现自定义的后置处理器完成属性的注入

FactoryBean创建Bean流程

上面写的bean创建都是使用@Component注解然后被扫描到的创建bean,Spring还提供了FactoryBean的创建模式 FactoryBean创建的比较特殊,没有实现SmartFactoryBean并且isEagerInit为false的都是懒加载模式。回到一开始的方法,遍历所有定义信息创建bean的时候有判断是不是工厂 image.png 在真正容器获取bean的时候才开始根据类型来容器中寻找bean

spring根据类型寻找bean

spring容器提供根据类型寻找bean的名称的接口 image.png 该接口的实现是遍历所有bean的定义信息,然后判断类型是否匹配 image.png 在FactoryBean判断的时候,FactoryBean提供了一个接口返回类型用于对比 image.png