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。
首先是 SpringBoot的 App类,如下:
1 1 @SpringBootApplication 2 2 public class App { 3 3 4 4 public static void main(String[] args) { 5 5 SpringApplication.run(App.class, args); 6 6 try { 7 7 System.in.read(); 8 8 } catch (IOException e) { 9 9 e.printStackTrace(); 1010 } 1111 } 1212 1313 @Bean(initMethod="start") 1414 BenzCar benzCar(Engine engine){ 1515 BenzCar car = new BenzCar(); 1616 car.engine = engine; 1717 return car ; 1818 } 1919 }
从上面第14行代码可以知道 benzCar 依赖 Engine对象,
以下是BenzCar 代码:
1public class BenzCar implements InitializingBean { 2 3 Engine engine; 4 5 public BenzCar(){ 6 System.out.println("BenzCar Constructor"); 7 if(engine==null){ 8 System.out.println("BenzCar's engine not setting"); 9 }else{ 10 System.out.println("BenzCar's engine installed"); 11 } 12 } 13 14 void start(){ 15 System.out.println("BenzCar start"); 16 engine.fire(); 17 } 18 19 @Override 20 public void afterPropertiesSet() throws Exception { 21 System.out.println("BenzCar initializingBean after propertieSet"); 22 if(engine==null){ 23 System.out.println("BenzCar's engine not setting, in initializingBean "); 24 }else{ 25 System.out.println("BenzCar's engine installed, in initializingBean"); 26 engine.fire(); 27 } 28 } 29 30 @PostConstruct 31 public void postConstruct(){ 32 System.out.println("BenzCar postConstruct"); 33 if(engine==null){ 34 System.out.println("BenzCar's engine not setting, in postConstruct"); 35 }else{ 36 System.out.println("BenzCar's engine installed, in postConstruct"); 37 } 38 } 39 40}
BenzCar类中有一个Engine对象成员, 在start方法中调用Engine的fire方法。
Engine接口代码如下:
1public interface Engine { 2 void fire(); 3}
Engine是一个接口,一般情况下,需要在App类中配置一个Engine的实现类bean才行,否则因为缺少Engine实例,spring启动时会报错。通过FactoryBean和动态代理,可以生成Engine接口的代理对象;结合BeanFactoryPostProcessor 接口,将FactoryBean动态添加到BeanFactory中,即可以给BenzCar配置上Engine接口代理对象。
为此新增一个 SpecialBeanForEngine类, 代码如下:
1 1 public class SpecialBeanForEngine implements BeanFactoryPostProcessor, BeanNameAware{ 2 2 3 3 String name; 4 4 5 5 @Override 6 6 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 7 7 8 8 BeanDefinitionRegistry bdr = (BeanDefinitionRegistry)beanFactory; 9 9 GenericBeanDefinition gbd = new GenericBeanDefinition(); 1010 gbd.setBeanClass(EngineFactory.class); 1111 gbd.setScope(BeanDefinition.SCOPE_SINGLETON); 1212 gbd.setAutowireCandidate(true); 1313 bdr.registerBeanDefinition("engine01-gbd", gbd); 1414 } 1515 1616 public static class EngineFactory implements FactoryBean<Engine>, BeanNameAware, InvocationHandler{ 1717 1818 String name; 1919 2020 @Override 2121 public Engine getObject() throws Exception { 2222 System.out.println("EngineFactory to build Engine01 , EngineFactory :"+ name); 2323 Engine prox = (Engine) Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{Engine.class}, this); 2424 return prox; 2525 } 2626 2727 @Override 2828 public Class<?> getObjectType() { 2929 return Engine.class; 3030 } 3131 3232 @Override 3333 public boolean isSingleton() { 3434 return true; 3535 } 3636 3737 @Override 3838 public void setBeanName(String name) { 3939 this.name = name; 4040 } 4141 4242 @Override 4343 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 4444 System.out.println("here is invoke engine:"+method.getName()); 4545 return null; 4646 } 4747 } 4848 4949 @Override 5050 public void setBeanName(String name) { 5151 this.name =name; 5252 } 5353 }
上面代码 8 ~ 13行,在postProcessBeanFactory方法中添加了 EngineFactory.class类的Bean。 EngineFactory 是一个FactoryBean,代码21-24行在getObject()方法中,使用动态代理生产Engine接口的代理对象。
在App类中增加SpecialBeanForEngine Bean, 如下
1 @Bean 2 SpecialBeanForEngine specialBeanForEngine(){ 3 return new SpecialBeanForEngine(); 4 }
程序运行结果如下:
1 1 SpecialBeanForEngine bean name :specialBeanForEngine 2 2 EngineFactory to build Engine01 , EngineFactory :engine01-gbd 3 3 BenzCar Constructor 4 4 BenzCar's engine not setting 5 5 BenzCar postConstruct 6 6 BenzCar's engine installed, in postConstruct 7 7 BenzCar initializingBean after propertieSet 8 8 BenzCar's engine installed, in initializingBean 9 9 here is invoke engine:fire 1010 BenzCar start 1111 here is invoke engine:fire
第1行: specialBeanForEngine bean 先生成
第2行: EngineFactory 调用 getObject()方法生产 Engine代理对象
第3行、4行: BenzCar调用构造方法,此时 engine属性还未被设置。
第5行、6: BenzCar调用@PostConstruct注解的方法,此时engine属性已经设置。
第7行: BenzCar调用 InitializingBean接口方法。
第10行: BenzCar调用 initMethod指定的方法,
第11行: BenzCar调用了代理对象的方法,SpecialBeanForEngine 类中第44行代码。
运行结果与前面描述的bean生命周期一致。至此,我们完成了只有Engine接口的情况下,在BenzCar中注入了Engine对象。
总结,postProcessBeanFactory接口、FactoryBean、动态代理,三者结合,可以在运行时动态的给BeanFactory中增加Bean,非常灵活的对spring容器进行扩展。很多开源项目在与spring整合时采用了类似方法。如果我们想自己写一些结合spring的框架程序,也可以采用类似方案。
参考:bean生命周期
代码已上传:https://github.com/shuangzh/springinsight.git
来源:周双的博客, 欢迎转载。(微信/QQ: 48689547, email:shuangzh@qq.com)
