一 . 前言
BeanPostProcessor 是 Spring 的核心组件之一 , Bean 实现 BeanPostProcessor 可以实现很多复杂的功能
二 . PostProcessor 的结构
2.1 接口方法
该接口中主要提供了2种 , 其中提供了前置调用和后置调用 . 还可以看到 , 这里通过 default 修饰 , 所以并不是强制重写的
2.2 常见实现类
这里可以看到 , AOP , 定时 , 配置等都实现了相关的集成
三 . Spring 源码深入分析
3.1 使用案例
这一部分来看一下 Spring 内部是如何使用 PostProcessor 特性的 , 这一部分以 ScheduledAnnotationBeanPostProcessor 为例.
PS : 后面就不看了 , 主要就是通过一个 ScheduledTask 运行 Runable 对象
从具体的使用上 , 不难看出 , 他是在创建Bean的时候去做补充的操作 , 那么下面来看一下具体的处理流程
这个流程在Bean 初始化流程 中进行了全面的跟踪 , 这里更关注其中的一些细节
3.2 Before/After 调用流程
入口一 : AbstractAutowireCapableBeanFactory #initializeBean调用
applyBeanPostProcessorsBeforeInitialization
applyBeanPostProcessorsAfterInitialization
其中流程也比较简单 , for 循环所有的 BeanPostProcessors 进行处理
3.3 BeanPostProcessors 的管理
类型一 : 手动添加的流程
可以通过手动添加的方式 ,实现 BeanPostProcessor 的添加 , 参考对象 AbstractApplicationContext
类型二 : Refresh 环节添加
哈哈 , 又到了这个地方 , 之前看 Refresh 代码的时候就注意到了这个地方 , 会注册相关的 BeanPostProcessors
源码注释非常清晰 ,这里就是简单翻译了一下
四 . 深入定制
4.1 添加 BeanPostProcessor
方法一 : 手动添加
PS : 当然 , 这种方式过于复杂 , 适用场景不多
方法二 : 直接继承接口
上面分析的时候也看到 , 实现了接口就自动添加了
五 .问题补充
5.1 与四种常见的初始化方式有什么区别 ?
回顾一下四种初始化运行的方式 :
实现 InitializingBean 接口方法 afterPropertiesSet
实现 ApplicationRunner 接口方法 run(ApplicationArguments args)
方法标注注解 @PostConstruct
@Bean(initMethod = "initMethod") 通过注解指定
调用的区别
调用次数: 四种方法只会调用一次 ,而 postProcessBeforeInitialization 和 postProcessAfterInitialization会在每个Bean创建的时候调用
调用时机: 集中在每个 BeaninitializeBean环节调用
六. 我们能用它干什么 ?
这里不讨论是否真的有场景会使用 ,只是发散思维 , 去思考如何利用他的特点去做点什么
6.1 结合设计模式
代理是 postProcess 最合适的使用之一 , AOP 即使用了他的特性进行的代理 , 我们可以模拟 AOP , 去做一个更偏向于业务的静态代理模式 .
同时也可以实现装饰器模式 , 对 Bean 的处理进行加强 .
Step 1 : 准备接口和实现类
Step 2 : 准备中间类
Step 3 : BeanPostProcessor 进行处理
补充 :
这里如果没有 , 则一定会抛出 BeanNotOfRequiredTypeException , 因为 Spring 会去坚持类是否匹配
这里我们属于静态代理 , 其实还可以更活用的使用cglib 动态代理
还有很多种整合设计模式的方式可以灵活使用
6.2 Manager 管理指定类型对象
这种方式是在 postProcessor 中对指定的Bean 进行一个管理记录
大概的使用方式是准备一个BeanManager , 然后在 postProcessor 中进行管理
补充 :
这是最简单的使用方式 , 相对更复杂的还可以整合注解 , 整合接口或者父类 , 或者仅记录class信息等方式 ,达到自己的业务效果
6.3 注入特殊属性
从图片中我们可以看到 , BeanPostProcessor 是在 PopulateBean 环节之后进行处理的 , 那么我们可以通过这个环节 , 对 Bean 中的属性进行修饰 , 常见的使用想法包括 :
为特定属性设置动态代理
从 Remote 端获取属性 , 并且设置
这个就比较好理解了 , 实际上这个时候包括RestTemplate 都已经加载完成 , JDBC 也可以使用 , 在这个时候完全可以从远端获取配置信息
**特殊对象的刷新有多种任意的使用 , 可以根据自己的业务灵活运用 **
6.4 其他思路
这里只是抛砖引玉 , 欢迎大佬们提出自己的想法
重构属性
定制化过程中对类进行覆盖
总结
注意点 :
applyBeanPostProcessorsBeforeInitialization 主要在 initializeBean 环节调用
applyBeanPostProcessorsAfterInitialization 除了initializeBean外还在多个环节被调用, 包括 getSingletonFactoryBeanForTypeCheck 等等几个 Factory 去实例化的过程中
避免循环 , ManagerPostProcessor 不会处理自己
BeanPostProcessor 在每个 bean 创建时都会调用 ,过多会影响启动效率
BeanPostProcessor 主要在populateBean 之后 , 注意前后顺序
领取专属 10元无门槛券
私享最新 技术干货