Spring的BeanFactoryPostProcessor
BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入,是不是很神奇? 本文将通过简单的例子,展现BeanFactoryPostProcessor的扩展能力。
一、bean生命周期简述
Spring Bean生命周期比较复杂,在此简化一下,如下图。
步骤1、 豆子工厂(BeanFactory)从xml文件、java配置或注解配置中读取“各种豆子的生产方法说明(BeanDefinition)”。
步骤2、 这些豆子分为“特殊豆子(实现spring指定的某些接口)”和“普通豆子”, 豆子工厂先生产出这些特殊豆子。
步骤3和4、 特殊豆子调用特定接口(例如BeanFactoryPostProcessor接口),可以对豆子工厂(BeanFactory)进行修改,或添加一些新豆子生产方法(即注册新的BeanDefinition到BeanFactory中)。
步骤5、豆子工厂(BeanFactory)执行getBean方法生产其他的普通裸豆子。(调用类的构造方法,或FactoryBean的getObject方法,以及@Bean注解的方法)
步骤6、设置豆子的依赖关系以及属性值。
步骤7、调用豆子的@PostConstruct指定的方法
步骤8、调用豆子的InitializingBean接口方法
步骤9、调用豆子的initMethod指定的方法。
总结上述过程, 我们可以得到以下执行顺序 : BeanFactoryPostProcessor ---> 普通Bean构造方法 ---> 设置依赖或属性 ---> @PostConstruct ---> InitializingBean ---> initMethod 。
二、BeanFactoryPostProcessor 代码例子
BenzCar类(奔驰汽车类)有成员属性Engine(发动机), Engine是接口,无具体的实现类。本代码例子,通过BeanFactoryPostProcessor ,FactoryBean,动态代理三项技术实现给BenzCar装配上Engine。
项目结构如下:
AppConfig类如下:
com.kaigejava.spring.beanlife.configcom.kaigejava.spring.beanlife.bean.BenzCarcom.kaigejava.spring.beanlife.bean.specialbean.SpecialBeanForEnginecom.kaigejava.spring.beanlife.service.Engineorg.springframework.context.annotation.org.springframework.context.annotation.AppConfig {
SpecialBeanForEngine (){
SpecialBeanForEngine()}
(initMethod=)
BenzCar (Engine engine){
BenzCar car = BenzCar()car.= enginecar }
}
从@Bean benzCar,我们可以看出,car需要一个engine对象。
以下是BenzCar 代码:
package com.kaigejava.spring.beanlife.bean;
import com.kaigejava.spring.beanlife.service.Engine;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
/**
* @author 凯哥Java
* @description
* @company
* @since 2022/11/10 15:03
*/
public class BenzCar implements InitializingBean {
public Engine engine;
public BenzCar(){
System.out.println(" BenzCar 无参构造器....");
if(engine == null){
System.out.println(" engine not setting ~~~~");
}else{
System.out.println(" engine 已经初始化");
}
}
void startCar(){
System.out.println(" BeanzCar start ====");
engine.fire();
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("BenzCar afterPropertiesSet method ... ");
if(engine == null){
System.out.println(" afterPropertiesSet engine not setting ~~~~");
}else{
System.out.println(" afterPropertiesSet engine 已经初始化");
engine.fire();
}
}
@PostConstruct
public void postConstruct(){
System.out.println(" BenzCar postConstruct....");
if(engine == null){
System.out.println(" postConstruct => engine not setting ~~~~");
}else{
System.out.println(" postConstruct => engine 已经初始化");
}
}
}
BenzCar 实现类 InitializingBean 类,重写了afterPorpertiesSet方法。有一个Engine对象成员, 在start方法中调用Engine的fire方法。
Engine接口代码如下:
com.kaigejava.spring.beanlife.serviceEngine {
()}
Engine是一个接口,一般情况下,需要在App类中配置一个Engine的实现类bean才行,否则因为缺少Engine实例,spring启动时会报错。通过FactoryBean和动态代理,可以生成Engine接口的代理对象;结合BeanFactoryPostProcessor 接口,将FactoryBean动态添加到BeanFactory中,即可以给BenzCar配置上Engine接口代理对象。
为此新增一个 SpecialBeanForEngine类, 代码如下:
com.kaigejava.spring.beanlife.bean.specialbeancom.kaigejava.spring.beanlife.factory.EngineFactoryorg.springframework.beans.BeansExceptionorg.springframework.beans.factory.BeanNameAwareorg.springframework.beans.factory.config.BeanDefinitionorg.springframework.beans.factory.config.BeanFactoryPostProcessororg.springframework.beans.factory.config.ConfigurableListableBeanFactoryorg.springframework.beans.factory.support.BeanDefinitionRegistryorg.springframework.beans.factory.support.GenericBeanDefinitionSpecialBeanForEngine BeanFactoryPostProcessorBeanNameAware {
String (String name) {
.= name}
(ConfigurableListableBeanFactory configurableListableBeanFactory) BeansException {
BeanDefinitionRegistry bdr = (BeanDefinitionRegistry) configurableListableBeanFactoryGenericBeanDefinition gbd = GenericBeanDefinition()gbd.setBeanClass(EngineFactory.)gbd.setScope(BeanDefinition.)gbd.setAutowireCandidate()bdr.registerBeanDefinition(gbd)}
}
在postProcessBeanFactory方法中添加了 EngineFactory.class类的Bean。 EngineFactory 是一个FactoryBean,代码21-24行在getObject()方法中,使用动态代理生产Engine接口的代理对象。
启动类:
com.kaigejava.spring.beanlifecom.kaigejava.spring.beanlife.config.AppConfigorg.springframework.context.annotation.AnnotationConfigApplicationContextMainApplication {
(String[] args) {
AnnotationConfigApplicationContext context = AnnotationConfigApplicationContext()context.register(AppConfig.)context.refresh()}
}
执行后结果:
源码:https://gitee.com/kaigejava/kaigejavastudy
相关文章
- TypeScript 中的 any、unknown、never 和 void
- 前端工程化指的是什么?
- React 合成事件的源码实现
- React 的调度系统 Scheduler
- 牛客刷题——剑指offer(第五期)
- JAVA IO——常用的类
- JAVA IO——FileOutputStream
- JAVA 多线程——实现创建线程的五种写法
- JAVA IO——文件拷贝
- 牛客刷题——剑指offer(第6期)
- 理解浏览器重绘和回流
- JAVA IO——文件字符说明
- 如何在 Canvas 上实现图形拾取?
- 蓝桥杯 ——省赛题(java 组)
- 蓝桥杯——java(b组)省赛
- Canvas 性能优化:脏矩形渲染
- 如何排查网页在哪里发生了内存泄漏?
- 理解 React 的调和器 Reconciler
- 蓝桥杯最后的冲刺篇(JAVA)
- 理解 React 的 commit 阶段