文章目录

  • BeanPostProcessor介绍
    • BeanPostProcessor执行流程
  • BeanPostProcessor使用
    • Book
    • BookProxyBeanPostProcessor
    • main
    • 全量代码
    • 执行结果
  • 源码解析
  • 总结

BeanPostProcessor介绍

BeanPostProcessor接口使得程序可以在Bean被初始化的前后执行自定义动作,如检查或更改Bean的属性值、包装即将注册到BeanFactorysingletonObjects中的原对象等。
BeanPostProcessor接口提供了如下方法:

方法 描述
Object postProcessBeforeInitialization(Object bean, String beanName) 在容器调用BeanInitializingBean#afterPropertiesSet()或自定义的init-method之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。
Object postProcessAfterInitialization(Object bean, String beanName) 在容器调用BeanInitializingBean#afterPropertiesSet()或自定义的init-method之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。

BeanPostProcessor执行流程

BeanPostProcessor的执行会在Bean实例化并装配好属性之后,before和after之间会插入BeanAfterPropertiesSet()init-method的执行。
下图能比较好的反应出过程:


BeanPostProcessor使用

接下来写个例子。全量代码会在最后贴出来,直接CV运行即可。

Book

Book类,它实现了InitializingBean接口,其afterPropertiesSet()方法仅输出一行信息用来记录执行流程;还有一个customInit()方法使其加入到Springinit-method的执行过程;该类还有一个show()方法,用来在后面的BeanPostProcessor处理器中对原始的Book对象生成一个代理类,该代理类将对show()方法进行增强处理,用来让咱们的BeanPostProcessor能实际干点事儿。

public class Book implements InitializingBean {private String name;private String author;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public void show() {System.out.printf("book#show():%s\n", this);}public void customInit() {System.out.printf("%-70s:%s{%s}%n", "------Book#customInit", this.getClass().getSimpleName(), this);}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +'}';}@Overridepublic void afterPropertiesSet() throws Exception {System.out.printf("%-70s:%s{%s}%n", "------Book#afterPropertiesSet", this.getClass().getSimpleName(), this);}}

BookProxyBeanPostProcessor

BookProxyBeanPostProcessor实现了BeanPostProcessor接口;在其postProcessBeforeInitialization()方法中对Book类型进行判断,如果是Book类型则使用CGLIB生成其代理,用来增强Book#show()方法,在其前后各打印一句话。

public class BookProxyBeanPostProcessor implements BeanPostProcessor {/*** 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.printf("%-70s:%s{%s}%n","------BookProxyBeanPostProcessor#postProcessBeforeInitialization",bean.getClass().getSimpleName(),bean);if (Book.class.equals(bean.getClass())) {System.out.printf("\033[1;33m%-70s:对[%s]的\033[1;31mshow()\033[1;33m方法进行增强 \033[0m%n","------BookProxyBeanPostProcessor#postProcessBeforeInitialization",bean.getClass().getSimpleName());Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Book.class);enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> {if (!method.equals(Book.class.getMethod("show"))) {return methodProxy.invokeSuper(obj, args);}System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行前");Object result = methodProxy.invokeSuper(obj, args);System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行后");return result;});Book book = (Book) enhancer.create();book.setName(((Book) bean).getName());book.setAuthor(((Book) bean).getAuthor());return book;}return bean;}/*** 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.printf("%-70s:%s{%s}%n","------BookProxyBeanPostProcessor#postProcessAfterInitialization",bean.getClass().getSimpleName(), bean);return bean;}
}

main

定义一个Book类型的GenericBeanDefinition,将Book#customInit()添加到BeanDefinition中,并设置MutablePropertyValues用于初始化后的属性装配。
同时将BookProxyBeanPostProcessor注册到容器中。

public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();GenericBeanDefinition bookBeanDefinition = new GenericBeanDefinition();bookBeanDefinition.setBeanClass(Book.class);bookBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);//指定为单例模式//设置属性bookBeanDefinition.setPropertyValues(new MutablePropertyValues().addPropertyValue(new PropertyValue("name", "《非暴力沟通》")).addPropertyValue(new PropertyValue("author", "马歇尔·卢森堡")));bookBeanDefinition.setInitMethodName("customInit");//设置初始化方法context.registerBeanDefinition("book", bookBeanDefinition);//注册BeanDefinitioncontext.registerBean("bookProxyBeanPostProcessor", BookProxyBeanPostProcessor.class);//注册Bean后处理器context.refresh();//刷新容器context.getBean("book", Book.class).show();
}

全量代码

package com.baiyang.beanpostprocessor;import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.context.support.GenericApplicationContext;public class BookProxyBeanPostProcessor implements BeanPostProcessor {/*** 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.printf("%-70s:%s{%s}%n","------BookProxyBeanPostProcessor#postProcessBeforeInitialization",bean.getClass().getSimpleName(),bean);if (Book.class.equals(bean.getClass())) {System.out.printf("\033[1;33m%-70s:对[%s]的\033[1;31mshow()\033[1;33m方法进行增强 \033[0m%n","------BookProxyBeanPostProcessor#postProcessBeforeInitialization",bean.getClass().getSimpleName());Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Book.class);enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> {if (!method.equals(Book.class.getMethod("show"))) {return methodProxy.invokeSuper(obj, args);}System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行前");Object result = methodProxy.invokeSuper(obj, args);System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行后");return result;});Book book = (Book) enhancer.create();book.setName(((Book) bean).getName());book.setAuthor(((Book) bean).getAuthor());return book;}return bean;}/*** 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.printf("%-70s:%s{%s}%n","------BookProxyBeanPostProcessor#postProcessAfterInitialization",bean.getClass().getSimpleName(), bean);return bean;}public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();GenericBeanDefinition bookBeanDefinition = new GenericBeanDefinition();bookBeanDefinition.setBeanClass(Book.class);bookBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);//指定为单例模式//设置属性bookBeanDefinition.setPropertyValues(new MutablePropertyValues().addPropertyValue(new PropertyValue("name", "《非暴力沟通》")).addPropertyValue(new PropertyValue("author", "马歇尔·卢森堡")));bookBeanDefinition.setInitMethodName("customInit");//设置初始化方法context.registerBeanDefinition("book", bookBeanDefinition);//注册BeanDefinitioncontext.registerBean("bookProxyBeanPostProcessor", BookProxyBeanPostProcessor.class);//注册Bean后处理器context.refresh();//刷新容器context.getBean("book", Book.class).show();}static class Book implements InitializingBean {private String name;private String author;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public void show() {System.out.printf("book#show():%s\n", this);}public void customInit() {System.out.printf("%-70s:%s{%s}%n", "------Book#customInit", this.getClass().getSimpleName(), this);}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +'}';}@Overridepublic void afterPropertiesSet() throws Exception {System.out.printf("%-70s:%s{%s}%n", "------Book#afterPropertiesSet", this.getClass().getSimpleName(), this);}}
}

执行结果


从执行结果即可反应出BeanPostProcessor的执行流程。

源码解析

spring版本:5.2.9

该节源码解析仅仅只讲关键的与BeanPostProcessor相关的位置。如果想要知其与BeanPostProcessor前后的细节,可以针对本节的所讲述的位置自行Debug进入详细阅读。

首先是Spring容器的经典入口:refresh()

然后调用AbstractApplicationContext所持有的实际BeanFactory(DefaultListableBeanFactory)句柄的preInstantiateSingletons()做Bean容器的初始化工作。


org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons:
进入getBean()方法,由于我们是新创建bean,所以流程将会是getBean()->doGetBean()->createBean()->doCreateBean()的流程,咱们一路DEBUG到doCreateBean():

由于我们重点是在了解BeanPostProcessor的内部执行流程上,所以上图隐藏了一些不太相关的代码,避免干扰;
此时还没有调用到BeanPostProcessor,所以从doCreateBean的执行流程可以看出,此时已经将Bean进行的实例化,并且装配好了属性值。
接着进入到关键方法exposedObject = initializeBean(beanName, exposedObject, mbd);


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

从上面的initializeBean()的流程可以看到我们首先调用了BeanPostProcessor#postProcessBeforeInitialization(),然后执行了invokeInitMethods()来处理bean的实现的InitializingBean接口的afterPropertiesSet()与自定义init-method;最后执行BeanPostProcessor#postProcessAfterInitialization();


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

从上面的方法可以看出BeanPostProcessor#postProcessBeforeInitialization是可以改变即将注册到BeanFactory 中的实际对象的。


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods

从上面的invokeInitMethods()可以看到包含了InitializingBean接口的处理与init-method的方法处理流程;
init-method方法最终会通过反射执行。


最后就是BeanPostProcessor#postProcessAfterInitialization()方法的执行:


至此initializeBean()方法执行结束返回到doCreateBean():

doCreateBean()initializeBean()返回的对象返回出去,一路回到getSingleton():
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

可以看到此时,已经将一个经过了BeanPostProcess处理的Bean对象注册到了BeanFactory中(在本例子里面是我们的BookProxyBeanPostProcessor创建的Book对象的代理类)。

总结

以上通过围绕BeanPostProcessor创建一个对指定Bean对象的代理对象,对其特定方法进行代理增强的例子,来介绍了BeanPostProcessor的应用。
同时,通过对源码的浅析来对BeanPostProcessor的执行前后流程进行了讲解。

Spring之Bean后处理器——BeanPostProcessor的使用与源码解析相关推荐

  1. Spring 注解面面通 之 @CrossOrigin 处理请求源码解析

      @CrossOrigin源码解析主要分为两个阶段:   ① @CrossOrigin注释的方法扫描注册.   ② 请求匹配@CrossOrigin注释的方法.   本文针对第②阶段从源码角度进行解 ...

  2. Spring的Autowired自动装配(XML版本+Annotation版本+源码+解析)

    http://moshowgame.iteye.com/blog/1607718 @Autowired自动装配 上面的例子我们用的都是手动装配的,如果DAO-Service一多那就很麻烦了,那么我们需 ...

  3. Spring 注解面面通 之 @CrossOrigin 注册处理方法源码解析

      参照<Spring 注解面面通 之 @RequestMapping 注册处理方法源码解析>,其讲解了@RequestMapping注释的处理方法注册过程,而@CrossOrigin是基 ...

  4. 品Spring:详细解说bean后处理器

    一个小小的里程碑 首先感谢能看到本文的朋友,感谢你的一路陪伴. 如果每篇都认真看的话,会发现本系列以bean定义作为切入点,先是详细解说了什么是bean定义,接着又强调了bean定义为什么如此重要. ...

  5. Spring Bean的生命周期以及IOC源码解析

    IOC源码这一块太多只能讲个大概吧,建议还是去买本Spring IOC源码解析的书来看比较好,我也是自己看源代码以及视频整理的笔记 Bean的生命周期大概可以分为四个阶段,具体的等会再说,先看看IOC ...

  6. Spring MVC源码解析——HandlerMapping(处理器映射器)

    Sping MVC 源码解析--HandlerMapping处理器映射器 1. 什么是HandlerMapping 2. HandlerMapping 2.1 HandlerMapping初始化 2. ...

  7. Spring源码解析(七)-Bean属性间的循环依赖

    首先复习一下前面学习的Spring容器启动的大致流程,首先Spring会先扫描所有需要实例化的Bean,将这些Bean的信息封装成一个个BeanDefinition,然后注册到BeanDefiniti ...

  8. Spring源码解析-bean实例化

    Spring源码解析-bean实例化 ​ 本文介绍Spring创建 bean 过程中的第一个步骤:实例化 bean. 1. Bean实例化源码 ​ 虽然实例化Bean有多种方式(包括静态工厂和工厂实例 ...

  9. Spring源码解析(五)-Bean的实例化流程(上)

    在前面已经完成了对需要实例化bean的收集并封装成BeanDefinition,并且将BeanPostProcess等组件进行了提前实例化.接下来就到了容器启动的最后一步,也是最复杂的一步-实例化be ...

  10. Spring 源码解析 - Bean创建过程 以及 解决循环依赖

    一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...

最新文章

  1. VC解析XML--使用CMarkup类解析XML
  2. 1、计算机系统硬件(面试小知识)
  3. 跨域解决方案之CORS
  4. python处理文本数据
  5. web语义化与h5新增标签
  6. Linux 命令(85)—— md5sum 命令
  7. 在线JWT Token解析解码
  8. Java词法分析器的设计与实现
  9. 泰勒公式和海森矩阵(Hessian-matrix)
  10. xy坐标转换为极坐标_xy坐标怎么换算(色坐标xy换算uv计算式)
  11. LaTex的箭头符号及命令
  12. 从零基础开始学习(一) esp32 micro python编程软件环境Thonny的安装
  13. ubuntu 打印git邮箱_win 10配置Ubuntu子系统—可以考虑放弃VMware了
  14. 很早以前就想要的东西,没想到今天会“妙手偶得”
  15. 救灾帐篷惊现高档小区
  16. 无线wifi如何远程唤醒?wake on lan网络唤醒及远程控制踩过的坑!
  17. 中山大学曾兆阳_实习派 | 曾兆阳: “宝藏男孩”的进阶之路
  18. GoogleCode中git push密码错误提示解决方案(Invalid username/password)
  19. Android8.0以上打开相机并裁剪图片
  20. Android 9 (P)版本解决VNDK library: XXX‘s ABI has EXTENDING CHANGES

热门文章

  1. Excel表VLOOKUP多个条件匹配数据
  2. DELL G3 3690耳机插入不显示,没声音
  3. 阿里云mysql勒索病毒处理_勒索病毒数据库恢复
  4. 降了还是涨了?瓶装水市场再秀迷幻操作
  5. win10设置开机默认开启数字小键盘2022
  6. 苏宁大数据怎么运营_苏宁智慧门店是什么?智慧门店是如何运作的?
  7. vue读取本地xlsx文件
  8. 酒桌上的那些礼仪规矩~
  9. Karen与测试 奇迹淫巧+快速幂
  10. 深度强化学习(二)强化学习算法的分类