Spring Bean 创建过程的 Hook
一. 概述
在《spring 的 IOC 使用以及原理》要讲述到 bean 的创建过程,但并没有涉及到创建 Bean 过程的 Hook。所谓 Hook,就是在创建 Bean 过程中提供接口,该接口可以影响创建 Bean 的过程。在 Spring 中的 Hook 是 BeanPostProcessor 接口,其下还有一些子接口。类图继承关系如下:
里面有两个单词概念需要澄清的,Instantiation 与 Initialization。Instantiation 是实例化,即 Bean 的创建。Initialization 是初始化,即对 Bean 的初始化,主要是属性的初始化。
BeanPostProcessor 有关针对 Bean 的初始化前后操作接口
InstantiationAwareBeanPostProcessor 有关针对 Bean 的实例化前后的操作接口
SmartInstantiationAwareBeanPostProcessor 有关预测 Bean 的最终类型,一般是用来做 AOP 的过程。
MergedBeanDefinitionPostProcessor 用来合并 BeanDefinition 对象,主要是对 BeanDefinition 的修改添加额外的信息
DesctructionAwareBeanPostProcessor 添加
二. Hook
BeanPostProcessor
postProcessBeforeInitialization Bean 的初始化前调用该方法。这里的初始化主要是指 InitializitingBean.afterPropertiesSet 方法,自定义 init-method 方法。具体的代码逻辑在 AbstractAutowireCapableBeanFactory.initializeBean 方法。
postProcessAfterInitialization Bean 的初始化后调用该方法。这里的初始化主要是指 InitializitingBean.afterPropertiesSet 方法,自定义 init-method 方法。具体的代码逻辑在 AbstractAutowireCapableBeanFactory.initializeBean 方法。但也有例外,当调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 返回一个不为空的 Bean 时,会直接该方法,接着就直接返回。
InstantiationAwareBeanPostProcessor
postProcessBeforeInstantiation 实例化前调用该方法,该方法一般是用来创建目标对象的代理实例。当返回的 bean 不为空,会接着调用 BeanPostProcessor.postProcessAfterInitialization 方法进行初始化。接着就结束整个 bean 的创建过程。这个回调方法将仅仅运用到真实类型,而不是工厂方法,因为工厂方法创建会 Bean 是动态的,而回调方法是静态的。主要的实现类是 AbstractAutoProxyCreator 的子类。
postProcessAfterInstantiation 实例化后,spring 属性填充(population)动作之前回调该方法。当返回 false 时,则无需进行属性的初始化,如 BeanDefinition.propertyValues 注入以及 autowiring 属性注入。当返回 true 时,属性则应该注入到对象当中。默认的返回 true。目前没有子类是返回 false 的。
postProcessPropertyValues 在容器对 Bean 的属性注入时前对提供的属性的值进行处理。一般是用来检查对象 Bean 的依赖是否满足,例如在 Bean 中含有 @Required 注解的属性。也可以用来替换 BeanDefinition.propertyValues 的对象,从而达到修改属性的效果。如子类 RequiredAnnotationBeanPostProcessor 对包含 @Required 注解的属性进行校验,是否满足。另外,有关 @Autowired 以及 @Resource 注解的属性的注入,其实现类分别是 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor。
SmartInstantiationAwareBeanPostProcessor
predictBeanType 预测从 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 回调方法返回的最终类型。
determineCandidateConstructors 决定指定的类中的候选构造方法,从而影响容器中的 Bean 的创建方式。
getEarlyBeanReference 对于早期访问指定的 Bean 而暴露引用,通常是为了解决循环问题。在 Bean 完全初始化之前提供一种机制,先暴露出 Bean 的封装。常规情况下,暴露出来的 Bean 是不变的。当暴露的 Bean 是与之前的 Bean 不一样时,这意味者对原始 Bean 进行了串改,返回其他类型。则需要暴露出一个方法给 spring 容器调用,去获取最终的类型,则就是 predictBeanType 的由来。通常情况下,该方法返回的是原始 Bean。AOP 代理类通常是在这个方法下进行对原始 Bean 的串改,实现类为 AbstractAutoProxyCreator 的子类。
MergedBeanDefinitionPostProcessor
postProcessMergedBeanDefinition 对指定的 Bean 的 BeanDefinition 进行合并操作,从而达到修改 BeanDefinition 的效果,从而影响 Bean 的创建过程。AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 实现就会将含有 @Autowired 和 @Resource 注解的属性保存到 BeanDefinition 中的 externallyManagedConfigMembers。目前没有找到针对这个 externallyManagedConfigMembers 属性进一步处理的代码。
DestructionAwareBeanPostProcessor 常规的实现类是 InitDestroyAnnotationBeanPostProcessor
postProcessBeforeDestruction 针对 Bean 销毁前调用的方法自定义销毁方法 @PreDestroy 标注的方法。
requiresDestruction 决定指定的实例 Bean 是否需要被销毁.
为了对以上的 HOOK 在 Spring 的 bean 过程被调用,画了粗糙的流程图,便以进一步理解以及掌握。
三. Hook 的实现类
ServletContextAwareProcessor 向实现 ServletContextAware 和 ServletConfigAware 接口的 Bean 的注入 ServletContext 和 ServletConfig 的属性
DefaultAdvisorAdapterRegistry 检测 spring 容器的 Bean,如果该 Bean 是 AdvisorAdapter 的实现类,则将其 Bean 注册到全局 Advisor 适配器对象中,提供给 AOP 信息
MethodValidationPostProcessor AOP 切面,针对方法中的返回参数以及入参的对象校验,当对象中包含了 @Validated 注解,会对方法中的对象进行约束校验。
AsyncAnnotationBeanPostProcessor 针对含有 @Async 注解标注的方法,进行切面,异步执行标注的方法;注意的是,@Async 标注的方法返回的类型是 CompletableFuture,Future 对象,这样子可以拿到异步执行后的结果,这个是属于阻塞型的;如果无需关心返回的结果,则返回的类型 Void;当然可以响应性编程,返回的类型为 ListenableFuture。
PersistenceExceptionTranslationPostProcessor 对类中有标注 @Repository 注解,进行拦截持久化异常处理;
BeanValidationPostProcessor 对 Bean 对象进行完整性校验
DataSourceInitializerPostProcessor 确保 DataSource 初始化后 DataSourceInitializer 也被初始化。主要是有关数据源的表以及数据的初始化。
ConfigurationPropertiesBindingPostProcessor 有关针对标注有 @ConfigurationProperties 注解的 Bean 对象,进行属性绑定。
ApplicationContextAwareProcessor 针对 EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware 等接口的实现类 Bean,进行方法调用
CommonAnnotationBeanPostProcessor 有关对 @Resource 注解进行属性注入的处理器
RequiredAnnotationBeanPostProcessor 有关对 @Required 注解依赖性校验的处理器
ScriptFactoryPostProcessor 有关动态脚本方面的处理器,这个不是很懂;先标志一下;
AutowiredAnnotationBeanPostProcessor 有关 @Autowired、@Value 注解标注的属性和方法进行注入的处理器
ImportAwareBeanPostProcessor 有关 ImportAware 接口实现 bean 的方法调用;
AbstractAutoProxyCreator 抽象类,有关创建 AOP 代理对象的处理器
ScheduledAnnotationBeanPostProcessor 有关处理 @Scheduled、@Schedules 注解标注的方法,将其方法放到线程定时执行;需要 @EnableScheduling 才能将其处理器注入到 spring 容器内;
四. 运用
我们基于 spring 开发过程,通常都会在属性标注 @Autowired 注解、@Resource 注解、@Value 注解,从而 Spring 自动的从容器里找到对应的对象并注入进去。
1. @Autowired
AutowiredAnnotationBeanPostProcessor 是 MergedBeanDefinitionPostProcessor 和 SmartInstantiationAwareBeanPostProcessor 接口的实现类。专门解析 Bean 对象中包含 @Autowired 注解、@Value 注解的属性和方法,然后进行对象注入。其覆盖的方法如下,并进行代码解读
determineCandidateConstructors 方法找出构造方法的条件逻辑比较多,我们基于不是 Kolin 编程的前提下进行梳理以及总结,主要从构造方法列表中找出含有 @Autowired、@Value 注解的构造方法列表,同时如果 Required 为 false 时,则会将无参构造方法加入进来。如果没有 @Autowired、@Value 注解的构造方法,且只有一个构造有参构造方法,则返回该有参构造方法。
有关对象的注入,逻辑比较简单,而且spring 的 IOC 使用以及原理以及类型转换也又简单讲过,里面稍微多了一些逻辑,这里不再过多讲解。至于从 spring 中找出对应的对象,逻辑比较复杂,将会有专门的一篇进行讲解。
2. @Resource
CommonAnnotationBeanPostProcessor 类是 InstantiationAwareBeanPostProcessor,DestructionAwareBeanPostProcessor,MergedBeanDefinitionPostProcessor 的实现类,其主要是对 @Resource 注解进行对象注入。其大体逻辑与 AutowiredAnnotationBeanPostProcessor 实现差不多,这里不再过多讲述。
值得注意的是,@Resource 注解中有 lookup 属性,其是有关 JNDI 获取对象的方式。常规下,如果我们不在 lookup 属性进行设值,spring 会自动从 spring 容器里检索对应类型的对象。如果有设值了,则从 JDNI 的上下文去查找对应的对象。有关 JDNI 的介绍,可以看Java JNDI使用详解。
3. AOP
AOP 是对对象进行封装成代理,从而对重复的代码进行有效的管理,达到切面效果。在 spring 容器,主要是在 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 接口以及 SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference 接口进行对 Bean 创建成代理对象。其实现类主要为 AbstractAutoProxyCreator 的子类,可以先进行查看。有关 AOP 代理的介绍,后续有针对 AOP 进行详细的解读。
五 总结
在创建 Bean 过程中,spring 提供了上层接口 BeanPostProcessor,对 Bean 初始化前后提供了回调方法。例如我们可以对 Bean 的属性进行非空校验 BeanValidationPostProcessor,例如对数据源初始化后,建表等操作,目前 spring 没有实现该处理器。InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的子类,主要是针对 Bean 的实例化前后提供了回调方法,可以影响 Bean 的创建以及属性注入等操作,同时也提供了对对象的属性注入提供了回调方法,针对 @Autowired、@Value、@Resource 等注解标注的属性以及方法进行对象注入。SmartInstantiationAwareBeanPostProcessor 接口是 InstantiationAwareBeanPostProcessor 的子接口,主要是提供了创建 Bean 的构造方法,从而影响 Bean 的创建。以及解决循环引用的问题,基于这个循环引用机制,可以实现 AOP 代理对象。而 MergedBeanDefinitionPostProcessor 以及 DestructionAwareBeanPostProcessor 接口,分别是针对 BeanDefinition 的合并以及对象销毁提供了回调方法,两个接口在 spring 创建 Bean 过程,不是最重要的接口,可以先忽略。
版权声明: 本文为 InfoQ 作者【邱学喆】的原创文章。
原文链接:【http://xie.infoq.cn/article/25864039e9284add9ee12dfc5】。文章转载请联系作者。
评论