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 @SpringBootApplication
2 public class App {
3
4 public static void main(String[] args) {
5 SpringApplication.run(App.class, args);
6 try {
7 System.in.read();
8 } catch (IOException e) {
9 e.printStackTrace();
10 }
11 }
12
13 @Bean(initMethod="start")
14 BenzCar benzCar(Engine engine){
15 BenzCar car = new BenzCar();
16 car.engine = engine;
17 return car ;
18 }
19 }

从上面第14行代码可以知道 benzCar 依赖 Engine对象,

以下是BenzCar 代码:

public class BenzCar implements InitializingBean {

    Engine engine;

    public BenzCar(){
System.out.println("BenzCar Constructor");
if(engine==null){
System.out.println("BenzCar's engine not setting");
}else{
System.out.println("BenzCar's engine installed");
}
} void start(){
System.out.println("BenzCar start");
engine.fire();
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("BenzCar initializingBean after propertieSet");
if(engine==null){
System.out.println("BenzCar's engine not setting, in initializingBean ");
}else{
System.out.println("BenzCar's engine installed, in initializingBean");
engine.fire();
}
} @PostConstruct
public void postConstruct(){
System.out.println("BenzCar postConstruct");
if(engine==null){
System.out.println("BenzCar's engine not setting, in postConstruct");
}else{
System.out.println("BenzCar's engine installed, in postConstruct");
}
} }

BenzCar类中有一个Engine对象成员, 在start方法中调用Engine的fire方法。

Engine接口代码如下:

public interface Engine {
void fire();
}

Engine是一个接口,一般情况下,需要在App类中配置一个Engine的实现类bean才行,否则因为缺少Engine实例,spring启动时会报错。通过FactoryBean和动态代理,可以生成Engine接口的代理对象;结合BeanFactoryPostProcessor 接口,将FactoryBean动态添加到BeanFactory中,即可以给BenzCar配置上Engine接口代理对象。

为此新增一个 SpecialBeanForEngine类, 代码如下:

 1 public class SpecialBeanForEngine implements BeanFactoryPostProcessor, BeanNameAware{
2
3 String name;
4
5 @Override
6 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
7
8 BeanDefinitionRegistry bdr = (BeanDefinitionRegistry)beanFactory;
9 GenericBeanDefinition gbd = new GenericBeanDefinition();
10 gbd.setBeanClass(EngineFactory.class);
11 gbd.setScope(BeanDefinition.SCOPE_SINGLETON);
12 gbd.setAutowireCandidate(true);
13 bdr.registerBeanDefinition("engine01-gbd", gbd);
14 }
15
16 public static class EngineFactory implements FactoryBean<Engine>, BeanNameAware, InvocationHandler{
17
18 String name;
19
20 @Override
21 public Engine getObject() throws Exception {
22 System.out.println("EngineFactory to build Engine01 , EngineFactory :"+ name);
23 Engine prox = (Engine) Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{Engine.class}, this);
24 return prox;
25 }
26
27 @Override
28 public Class<?> getObjectType() {
29 return Engine.class;
30 }
31
32 @Override
33 public boolean isSingleton() {
34 return true;
35 }
36
37 @Override
38 public void setBeanName(String name) {
39 this.name = name;
40 }
41
42 @Override
43 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
44 System.out.println("here is invoke engine:"+method.getName());
45 return null;
46 }
47 }
48
49 @Override
50 public void setBeanName(String name) {
51 this.name =name;
52 }
53 }

上面代码 8 ~ 13行,在postProcessBeanFactory方法中添加了 EngineFactory.class类的Bean。 EngineFactory 是一个FactoryBean,代码21-24行在getObject()方法中,使用动态代理生产Engine接口的代理对象。

在App类中增加SpecialBeanForEngine  Bean, 如下

    @Bean
SpecialBeanForEngine specialBeanForEngine(){
return new SpecialBeanForEngine();
}

程序运行结果如下:

 1 SpecialBeanForEngine bean name :specialBeanForEngine
2 EngineFactory to build Engine01 , EngineFactory :engine01-gbd
3 BenzCar Constructor
4 BenzCar's engine not setting
5 BenzCar postConstruct
6 BenzCar's engine installed, in postConstruct
7 BenzCar initializingBean after propertieSet
8 BenzCar's engine installed, in initializingBean
9 here is invoke engine:fire
10 BenzCar start
11 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的框架程序,也可以采用类似方案。

转载自:https://www.cnblogs.com/piepie/p/9061076.html

Spring高级进阶:BeanFactoryPostProcessor的更多相关文章

  1. 肝了75天,五万五千字,《Spring Boot 进阶》专栏文章整理成册,分享~

    前言 Spring Boot 这个专栏从早期的体系构建到写完,总共花费了七十五天,期间由于工作及个人原因停更了一段时间,没办法,工作实在太忙了. 很多人疑惑了,为什么源码介绍过了就结束了?高级的部分不 ...

  2. 潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师

    潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师 讲的不错,可以学习 下面是教程的目录截图: 下载地址:http://www.fu83.cn/thread-283-1-1.htm ...

  3. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  4. 高级进阶DB2(第2版)——内部结构、高级管理与问题诊断

    <高级进阶DB2(第2版)——内部结构.高级管理与问题诊断> 基本信息 作者: 牛新庄    出版社:清华大学出版社 ISBN:9787302323839 上架时间:2013-7-3 出版 ...

  5. MEF高级进阶

    MEF高级进阶   好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四 ...

  6. Spring高级装配

    Spring高级装配 目录 一.Profile(根据开发环境创建对应的bean) 二.条件化的创建bean(根据条件创建bean) 三.处理自动装配歧义性(指定首选bean.限定符限制bean) 四. ...

  7. .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码. 通过一系列优化最终达到两个效果,1.通过代码块来控制事务(分布式事务),2.通过委托优化Tran ...

  8. 《Android高级进阶》读书笔记

    <Android高级进阶>是据我所知的市面上唯一一本技术工具书,比较的高大全,作者的目的是为了对全领域有个初步的概念 No1: 在Android系统中,拥有事件传递处理能力的类有以下三种 ...

  9. Spring高级装配(一) profile

    Spring高级装配要学习的内容包括: Spring profile 条件化的bean声明 自动装配与歧义性 bean的作用域 Spring表达式语言 以上属于高级一点的bean装配技术,如果你没有啥 ...

随机推荐

  1. 多层nginx中的压缩问题 api接口>1M数据的返回浏览器 网关

    基础 前端异步请求,局部刷新,加大最大等待时间 nginx开启压缩 进阶 多级nginx的压缩 实践测试: 每级都要开启压缩 gizp on: 最外层开启,但最内层没有开启 最外层没有开启 最外层.最 ...

  2. CRM 线索 客户 统称为 资源 客户服务管理篇 销售易

    线索 客户 统称为 资源 - 国内版 Binghttps://cn.bing.com/search?FORM=U227DF&PC=U227&q=%E7%BA%BF%E7%B4%A2+% ...

  3. python+opencv抠图并旋转(根据坐标抠图)

    import cv2 import numpy as np def subimage(image, center, theta, width, height): theta *= np.pi / 18 ...

  4. PHPStorm提示:phpdoc comment doesn't contain all necessary @throw tag(s)

    选择Settings => Editor => Inspection, 选择PHP => PHPDoc => Missing @throws tag(s) ,把后面的勾勾去掉就 ...

  5. Error-JavaScript:SCRIPT1007: 缺少 ']'

    ylbtech-Error-JavaScript:SCRIPT1007: 缺少 ']' SCRIPT1007: 缺少 ']' 1.返回顶部 · if (flag) { return eval(&quo ...

  6. kubernetes 亲和性调度详解

    文章目录 1 概述: 2 场景一:调度到一组具有相同特性的主机上(label+nodeSelector) 3 场景二:部署的应用不想调度到某些节点上(nodeaffinity) 4 场景三:部署的应用 ...

  7. 我非要捅穿这 Neutron(二)上层资源模型篇

    目录 文章目录 目录 Neutron 的资源模型 Network 运营商网络和租户网络 创建运营商网络 创建租户网络 创建外部网络 Network 小结 Subnet IP 核心网络服务 Subnet ...

  8. 【Mybatis】MyBatis之Generator自动生成代码(九)

    MyBatis Generator 简介 MyBatis Generator 连接数据库表并生成MyBatis或iBatis文件.这有助于最大限度地减少使用MyBatis时为数据库文件创建简单CRUD ...

  9. wave数据集的回归曲线

    wave数据集的回归曲线 import matplotlib.pyplot as pltimport mglearnfrom scipy import sparseimport numpy as np ...

  10. PAT 甲级 1073 Scientific Notation (20 分) (根据科学计数法写出数)

    1073 Scientific Notation (20 分)   Scientific notation is the way that scientists easily handle very ...