一篇文章带你玩转Spring bean的终极利器

作者:张涛 时间:2022-08-20 10:47:33 

前言

前面的篇幅里有提到通过InitializingBean和Disposable等接口可以对bean的初始化和销毁做一些自定义操作,那么有一点要注意,那仅仅是在bean被容器实例化之后的操作,在spring的世界里,要想对实例化这个过程做点什么,作为一个普通业务的开发人员,显然不需要去继承ApplicationContext或者BeanFactory,因为spring container为我们提供了一些接口,让我们以插件的形式去扩展BeanFactory对bean的初始化操作,其中就有我们今天的主角——BeanPostProcessor(以下简称bpp)接口。

源码,先睹为快

一篇文章带你玩转Spring bean的终极利器

这个用法很简单,它只有两个方法,我们实现自己的BeanPostProcessor,Spring能自动注册到容器中。

其中before方法是在bean实例化之后,属性设置之后但在初始化方法之前执行;after方法是在各种初始化方法之后执行。

说到这里可能有人会想,这跟生命周期中的其它初始化接口有啥区别?其它的初始化方法也可以修改bean啊,这个问题问得好,那么我们来说下这个接口与InitializingBean Disposable接口以及自定义的init destroy方法的本质区别

  • bpp的两个方法是有返回值Object的,这恰恰是问题的关键,这个bean就是我们要修改的bean,这样一来,我们就可以修改bean实例本身,或替换,或wrap成一个proxy bean(Spring中的aop机制多是这么干),而其它的初始化接口的返回为void,因此它们理论上只能修改bean的状态,能做的东西相当受限制。

  • bpp是以扩展插件的形式被Container执行,不需要bean本身去做什么(bean本身不用实现这个接口),所以这个插件跟bean在代码上不耦合

  • 在执行方式上也完全不同,bpp是作为Spring container的一个扩展,在容器初始化bean的过程过,对每个bean都会执行一次,而初始化接口,由于是特定的bean实现的,所以与其它的bean无关,只对初始该类型的bean执行。简而言之就是,虽然都是由容器执行对bean的操作,bpp是扩展的容器本身行为,而初始化接口是扩展bean的行为后被容器执行的。

在这里有两种特殊的bpp不得不说,假设你需要自定义一个类似于@Autowire或者@Inject的注入功能的注解的时候(你可能会用到InjectionMetadata),普通的bpp可能就满足不了你的需要了,你可能用到两个特殊的bpp。

MergedBeanDefinitionPostProcessor(以下简称mbdpp)

InstantiationAwareBeanPostProcessor(以下简称iabpp)

他们都是继承自bpp,但在spring bean 创建的过程中切入点不同于普通的bpp。

InstantiationAwareBeanPostProcessor接口

一篇文章带你玩转Spring bean的终极利器

 看注释

一篇文章带你玩转Spring bean的终极利器

postProcessBeforeInstantiation方法

查阅AbstractAutowireCapableBeanFactory的createBean方法(这个方法是Spring容器创建bean的核心方法),可以看到,postProcessBeforeInstantiation是在bean实例化之前,postProcessAfterInstantiation是在实例化之后属性设置以及autowire注入之前,它一般是spring框架内部使用,但在这里大有可为,用postProcessBeforeInstantiation可以生成代理对象( 一般作法是让postProcessorBeforeInstantiation方法返回不为null,这样就会中断后续创建bean实例的过程,会以这个方法返回的对象作为bean实例),看源码:

一篇文章带你玩转Spring bean的终极利器

postProcessPropertyValues方法

用postProcessPropertyValues 可以完成对属性的各种操作,注解中元数据的解析等,Spring的@Autowire注入,JSR330的@Inject以及JSR250的@Resource等注入操作都是通过这个方法完成。

这接口的用处在spring底层较多,有兴趣的同学可以翻阅源码,以下是两个比较典型的实现。

AutowiredAnnotationBeanPostProcessor
AbstractAutoProxyCreator

MergedBeanDefinitionPostProcessor接口

一篇文章带你玩转Spring bean的终极利器

这个接口传入了一个RootBeanDefinition,这里允许我们修改bean的定义,@AutuwiredAnnotationBeanPostProcessor通过实现这个方法检查并注册需要注入的成员。

BeanFactoryPostProcessor(bfpp)

除了BeanPostProcessor还有一种想必大家都知道,那就是BeanFactoryPostProcessor

bfpp是作为beanFactory的一个很重要扩展插件,可以用来自定义BeanDefination的。它与bpp主要区别在于:

  • bpp是处理的bean实例,bfpp是处理bean的定义

  • bfpp能读取和修改bean的定义(BeanDefination),比如说在配置中属性值用到的占位符${}就是PropertyPlaceholderConfigurer通过实现bfpp来实现的

  • bpp处理的则是新鲜出炉并且设置好属性的bean的实例(上边提到iabpp和mdbpp的两种特殊的bpp除外)

好了,说了这么多,来看下Spring创建bean的大致流程图,这里只标出了比较关键的节点

 一篇文章带你玩转Spring bean的终极利器

来源:https://mp.weixin.qq.com/s/29EaSBRGeCofO94tQOn_JA

标签:spring,bean,源码
0
投稿

猜你喜欢

  • Java C++ 算法题解leetcode145商品折扣后最终价格单调栈

    2023-09-16 23:29:42
  • mybatis @Alias注解在类上的使用方式(推荐)

    2023-11-20 00:30:03
  • 浅谈JavaWeb中的web.xml配置部署描述符文件

    2023-11-12 00:14:13
  • java实现简单的webservice方式

    2023-11-25 03:59:58
  • Java为实体类动态添加属性的方法详解

    2023-09-01 05:31:43
  • spring boot thymeleaf 图片上传web项目根目录操作步骤

    2023-11-23 10:50:46
  • Android中TimePicker与DatePicker时间日期选择组件的使用实例

    2023-08-07 01:35:15
  • Springboot使用POI实现导出Excel文件示例

    2021-09-22 08:18:31
  • Spring Security实现自动登陆功能示例

    2023-01-29 15:31:55
  • Android 沉浸式状态栏及悬浮效果

    2023-07-29 23:03:15
  • Java内部类及其特点的讲解

    2023-06-09 19:39:41
  • C语言实现两个矩阵相乘

    2023-07-22 12:41:20
  • java实现短信验证码5分钟有效时间

    2023-08-30 18:42:26
  • Java调用第三方http接口的常用方式总结

    2023-11-06 22:47:24
  • java并发编程之ThreadLocal详解

    2023-03-15 11:44:33
  • Java使用Preference类保存上一次记录的方法

    2023-05-08 01:49:14
  • Java冒泡排序及优化介绍

    2023-11-11 13:05:51
  • IDEA安装后找不到.vmoptions文件的问题及解决

    2023-10-05 22:43:44
  • Java ThreadLocal的使用详解

    2023-11-29 04:48:43
  • Java ArrayList中存放引用数据类型的方式

    2023-11-16 15:23:46
  • asp之家 软件编程 m.aspxhome.com