Spring 的 bean 初始化过程
前言
Spring 框架最基础来说, 是一个 DI(依赖注入) 框架. 我们把我们的程序中用到的实体对象, 也就是我们常说的 bean, 放在 Spring 框架中维护, 当我们用到这些 bean 的时候, 可以在程序的任何地方来获取.
Spring 封装了复杂的逻辑, 留给了我们很多便利又简单的方式来使用, 这正是我们使用 spring 框架的原因. 但是这也带来了一些问题, 我们对内部几乎一无所知, 当遇到复杂情况或者问题的时候, 往往无从下手. 而且, 随着 spring 很多自动化配置的出现, 和我们印象中的一些配置方式产生了冲突或重复, 即使在通常情况下能够启动运行, 我们也不敢说我们的配置绝对正确没有问题. 这个时候, 我觉得我们应该多了解一些内部实现, 这对于我们排查异常问题, 检查项目正确性都很有帮助.
那么我们在使用时, 就涉及到两个方面:
- 定义和注册 bean
- 获取 bean
我们从这两个方面来讲.
定义和注册 bean
我们在使用 spring 的时候, 有这么几种常用的定义 bean 的方式:
- xml 中来定义 bean 标签
- 通过注解扫描, 比如 @Service 这种类.
- 定义 Configuration 类, 在类中提供 @Bean 的方法来定义.
- 使用纯粹的 programmatically 的方式来定义和注册.
前三种方式, 我们经常使用, 我们简单看一下第四种方式是什么样子的
// 新建一个工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 新建一个 bean definition
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(SomeService.class)
.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
// 注册到工厂
factory.registerBeanDefinition("someService", beanDefinition);
// 自己定义一个 bean post processor. 作用是在 bean 初始化之后, 判断这个 bean 如果实现了 ApplicationContextAware 接口, 就把 context 注册进去..(先不要管 context 哪来的...例子嘛)
factory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware) {
GenericApplicationContext context = new GenericApplicationContext(factory);
((ApplicationContextAware) bean).setApplicationContext(context);
}
return bean;
}
});
// 再注册一个 bean post processor: AutowiredAnnotationBeanPostProcessor. 作用是搜索这个 bean 中的 @Autowired 注解, 生成注入依赖的信息.
AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
autowiredAnnotationBeanPostProcessor.setBeanFactory(factory);
factory.addBeanPostProcessor(autowiredAnnotationBeanPostProcessor);
// getBean() 时, 初始化
SomeService SomeService = factory.getBean("someService",SomeService.class);
SomeService.doSomething();
我们定义了一个 BeanDefinition, 注册到了一个 BeanFactory 中; 然后从 BeanFactory 中获得这个 bean, 调用这个 bean 当中的方法.
事实上, 定义 BeanDefinition 并注册到 BeanFactory 的这个过程, 就是 bean 的定义和注册 , 我们通常使用 spring 时并不是把一个 bean 的实例注册, 而是一个 BeanDefinition.
而在第一次从 BeanFactory 当中 getBean() 时, 这个 bean 的实例才会真正生成. 这个部分我们在第二部分讲.
BeanFactory
BeanFactory 是专门用来获取 bean 的接口. 他又诸多的实现, 其中 ConfigurableListableBeanFactory 是最常用的.
另外 Context 类也实现了 BeanFacotry 的接口, Context 是通过继承和组合的方式对 BeanFactory 的一层封装, 避免直接访问到 BeanFactroy, 保证运行时不能随意对 BeanFactroy进行修改. 除此之外还提供了更多的功能: 它不仅有 BeanFactory 管理 bean 池的功能, 还要负责环境配置管理, 生命周期管理, 复杂的初始化操作等.
BeanFactory 的接口成层次比较复杂, 我总结了下主要的有以下功能的接口
-
BeanFactroy
最基础的 BeanFactory, 提供了根据 name , type 等获取一个 bean 对象的能力
-
ListableBeanFactory
继承 1, 额外提供了列出所有bean对象的能力
-
HierarchialBeanFacotry
继承 1, 额外使了 factory 拥有一个 parent factory 的能力, 可以存在层级关系
-
singletonbeanRegistry
提供了单例对象缓存的能力
-
AutowireCapableBeanFacory
继承 1, 提供了在创建对象时, 通过set方式给 bean 初始化 autowired 或者声明了 dependon 的成员
-
ConfigurableBeanFactory
继承 2 和 3, 给 factory 提供了很多配置的方法, 比如设置 BeanPostProcessor
-
AliasRegistry
支持了多个别名
最终经过各种组合, 我们一般用到实现类就两个
-
StaticListableBeanFactory
实现 ListableBeanFactory, 是最简单的 Beanfactory. 直接注册 bean 实例到 factory 中的 map 中, 获取时直接从 map 中返回. 如果我们自己写的简单项目需要做基本的依赖注入管理, 可以使用这一个.
-
DefaultListableBeanFactory
我们平常项目用到的, 通过 BeanDefinition 定义类, 在第一次 get 时实例化, 并在实例化过程中同时实例化依赖类, 并做属性填充, 并执行一些初始化前后的 processor.
我们平常从 xml 中, 代码注解中定义的 bean, 通过 XmlBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 生成 bean definition 注册到 DefaultListableBeanFactory中.
我们就从 DefaultListableBeanFactory 来讲初始化的过程, 如果想通过这个类来创建 bean , 就需要通过 xml配置, bean配置的方式生成 bean definition, 这是个怎样的东西呢.
BeanDefinition
完全的定义了一个 bean 的实例化, 初始化方式.
我们可能会关心的内部属性
parentName: String // bean 的名字
beanClassName: String // bean 类型名字
scope: String // 作用域, 默认的有 singleton 和 proto, 前者是我们常用的单例, 后者是每次新建一个 bean. 子类可以实现更多的scope, 比如 session, request.
lazyInit: boolean // 是否需要懒加载, 通常是由有context的应用来控制.
dependsOn: String[] // 依赖的 bean name, 跟是否要注入没关系, 有时是因为要控制 bean 的初始化顺序
autowireCandidate: boolean // 是否可以被 autowire, 默认true
primary: boolean // autowire 的优先级, 如果有多个 candidate, 会选 primary
factoryBeanName: String // 如果实例需要由工厂创建, 工厂 bean 的 name.
factoryMethodName: String // 工厂 bean 的 类型.
constructorArgumentValues: ConstructorArgumentValues // 构造函数参数表
propertyValues: MutablePropertyValues // 属性表
singleton: boolean
prototype: boolean
abstract: boolean
role: int // bean 的定义者, 0: 由application定义, 即用户定义的. 1: support, 框架支持模块. 2: infrastructure, 框架的基础组件
description: String
resourceDescription: String // 定义来源
originatingBeanDefinition: BeanDefinition // 加工后的 BeanDefinition 保存原始 BeanDefinition.
beanClass: Class<?> // load bean 的 class 之后, 把 class 类型保存这里
abstract: boolean
autowireMode: int // 可以被autowire按类型, 按名称等
resolvedAutowireMode: int // 解决自己autowire属性时用按类型注入, 还是按构造参数传入
dependencyCheck: int // 依赖 check 策略, 全都 check, 还是只 check 引用类型, 还是只 check 简单类型, 或者不 check
initMethodName: String // 自定义的初始化方法
destroyMethodName: String // 销毁方法
synthetic: boolean // true 表示不需要多余的 实例化,初始化前后处理.
resource: Resource // 这个 bean definition 的 resource 引用
Bean的实例化过程
大概流程及说明, 以 singleton scope 的 bean 为例
-
get bean from singleton cache
首先从 singleton cache 获取对象, 如果有, 说明初始化过, 直接返回, 如果没有, 继续
-
if return bean, return
-
if null, go on
-
-
create merged definition
找到 bean 的 definition (bd), 然后生成 merged bean definition (mbd). 这个主要是因为 bd 可以有 parent, 这个步骤的作用就是把 bd 和 它的 parent bd (如果有的话), 进行merge, 生成 mbd, 之后就要根据这个 mbd 来实例化和初始化 bean.
-
check bean definition
检查 mbd , 把 mbd 中 dependsOn 的 bean 都先初始化.
-
get singleton, if not found, then create bean:
再次从 singleton cache 中获取 bean, 跟第 1 步方法参数不同, 这一步如果没有, 则会真正 create bean
-
resolve class
查找并 load 这个 bean 的 class
-
resolveBeforeInstantiation
在真正的实例化之前进行一次预先操作, 目的是给用户一个机会来进行非正常的实例化, 用户注入的 InstantiationAwareBeanPostProcessor 子类, 可以做一些 proxy, mock, 来取代真实的实例化返回, 如果没有产生 bean, 则继续往下走去正常的实例化阶段.
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
- if return bean, BeanPostProcessor.postProcessAfterInitialization(), then return bean.
- if return null, go on
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
-
do create bean
-
create instance
真正的实例化, 调用 mbd 中定义的 factoryMethod, 或者类的构造方法, 来生成对象.
-
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition // 比如autowire等 注解注入 mbd
对 mbd 进行初始化前的操作, 比如扫描 class 定义, 找到 @autowired 注解来生成注入信息存放在 mbd 中.
-
add early singleton cache
这一步主要是为了解决循环引用, 再把未初始化的 bean 的 reference 提供出来.
-
populate bean
填充属性阶段, properties values (pvs), 这一大步骤中的前三小步都是在构造 pvs, 并在最后一步 apply 进去
-
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
-
autowire
把能够 set 的的属性写入 pvs
-
InstantiationAwareBeanPostProcessor.postProcessPropertyValues()
把一些特殊属性写入, 比如没有 set 的 autowired 属性, 一些 @Value 的属性
-
apply property values
-
-
initialize bean
实例化完毕之后, 进行初始化.
-
aware beanName, classLoader, beanFactory
如果有需要, 把这三个特殊的对象放到 bean 里
-
BeanPostProcessor.postProcessBeforeInitialization()
-
init
真正的初始化操作
- 如果 bean 是 InitializingBean, afterPropertiesSet()
- 调用自定义 init
-
BeanPostProcessor.postProcessAfterInitialization()
-
-
register disposable bean
-
-
我们在这个过程中能做的
-
InstantiationAwareBeanPostProcessor
实现这个接口的类, 可以在类的实例化阶段, 做一些操作.
这个接口有三个方法:
-
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
在实例化之前进行一些操作, 目的是提供一个机会由这个方法来实例化对象. 比如 proxy, mock
-
boolean postProcessAfterInstantiation(Object bean, String beanName)
bean set属性前执行, 如果返回false, 将会跳过属性处理. 这个一般都是返回true.
-
PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
属性构造完成, apply 到对象前执行, 传入 pvs 并返回 pvs, 有机会对 pvs 进行处理. 比如 required 检测在这一步.
-
-
BeanPostProcessor
这个接口有两个方法:
-
Object postProcessBeforeInitialization(Object bean, String beanName)
在初始化之前 传入 bean 并返回 bean, 但返回的 bean 可以被包装或者替换
-
Object postProcessAfterInitialization(Object bean, String beanName)
同上, 也可以做一些 bean 初始化完成后的回调. 比如可以监听每一个 bean 的初始化时机.
-
交流
欢迎加入群 661035226,gradle,spring,activiti 交流
网友评论