概念

Bean创建过程中的“实例化”与“初始化”名词

  • 实例化(Instantiation): 要生成对象, 对象还未生成.
  • 初始化(Initialization): 对象已经生成.,赋值操作。

BeanPostProcessor :

发生在 BeanDefiniton 加工Bean 阶段. 具有拦截器的含义. 可以拦截BeanDefinition创建Bean的过程, 然后插入拦截方法,做扩展工作.

  • postProcessBeforeInitialization初始化前置处理 (对象已经生成)
  • postProcessAfterInitialization初始化后置处理 (对象已经生成)

InstantiationAwareBeanPostProcessor: 继承于BeanPostProcessor ,所以他也是一种参与BeanDefinition加工Bean过程的BeanPostProcessor拦截器, 并且丰富了BeanPostProcessor的拦截.

  • postProcessBeforeInstantiation 实例化前置处理 (对象未生成)
  • postProcessAfterInstantiation 实例化后置处理 (对象已经生成)
  • postProcessPropertyValues 修改属性值。(对象已经生成)

总的来说:

BeanPostProcessor定义的方法是在对象初始化过程中做处理。

InstantiationAwareBeanPostProcessor定义的方法是在对象实例化过程中做处理

发生时机

1.postProcessBeforeInstantiation 调用时机

BeanDefinition创建Bean的开端是在createBean()方法也就是流水线的开始处。

	    @Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...省略
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
} Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}

看这段英文注释: Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.

给BeanPostProcessor一个机会去返回一个代理对象. 就是在流水线doCreateBean()生成对象之前, 给用户自定义返回一个对象的机会.

再看看resolveBeforeInstantiation(beanName, mbdToUse)是如何处理自定义返回对象的.

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
  • 判断是有有InstantiationAwareBeanPostProcessor的BeanPostProcessor
  • 有则调用的是InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()实例化前置处理方法,也就是在Bean没有生成之前执行。(注意:这里所说的是Bean未生成指的是Bean没有走spring定义创建Bean的流程,也就是doCreateBean()方法。)
  • 如果postProcessBeforeInstantiation()返回的对象不为空, 那么对象的生成阶段直接完成
  • 接着调用postProcessAfterInitialization()[初始化后置处理] 处理这个对象.
  • 如果为空?则走流水线doCreateBean()创建对象, 对象初始化.

2.postProcessAfterInstantiation调用时机

上文resolveBeforeInstantiation()没有返回bean.则走流水线创建Bean

doCreateBean(beanName, mbdToUse, args)创建对象,会经过populateBean(beanName, mbd, instanceWrapper)方法。

populateBean(beanName, mbd, instanceWrapper)依次执行postProcessAfterInstantiation() postProcessPropertyValues()

3.postProcessBeforeInitialization调用时机

doCreateBean(beanName, mbdToUse, args)创建对象,会经过initializeBean(beanName, exposedObject, mbd);方法。

initializeBean(beanName, exposedObject, mbd); 会首先执行 postProcessBeforeInitialization()方法

4.postProcessAfterInitialization

initializeBean(beanName, exposedObject, mbd); 会首先执行 postProcessAfterInitialization()方法

总结:

实例化--->初始化

  • BeanPostProcessor定义的方法是在对象初始化过程中做处理。
  • InstantiationAwareBeanPostProcessor定义的方法是在对象实例化过程中做处理

会形成两种执行流程完成BeanDefinition 创建Bean.

  1. postProcessBeforeInstantiation()--自定义对象-->postProcessAfterInitialization();
  2. postProcessBeforeInstantiation() -->postProcessAfterInstantiation-->postProcessBeforeInitialization()-->postProcessAfterInitialization()

我们看出:postProcessBeforeInstantiation一定执行, postProcessAfterInitialization一定执行.

至此:不知道读者是否体会到了InstantiationAwareBeanPostProcessor与BeanPostProcessor接口 以及其定义的4个方法的妙处.

四个方法执行的顺序对理解spring创建流程有着重要意义。

BeanPostProcessor 本身就是一种拦截的设计思想. 拦截的目的就是做额外的操作, 即 扩展。

欢迎大家关注我的公众号【源码行动】,最新个人理解及时奉送。

spring源码系列7:Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别的更多相关文章

  1. Spring源码系列 — BeanDefinition

    一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...

  2. 事件机制-Spring 源码系列(4)

    事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...

  3. Ioc容器依赖注入-Spring 源码系列(2)

    Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...

  4. Ioc容器BeanPostProcessor-Spring 源码系列(3)

    Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...

  5. AOP执行增强-Spring 源码系列(5)

    AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...

  6. Ioc容器beanDefinition-Spring 源码系列(1)

    Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...

  7. Spring源码系列 — 注解原理

    前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...

  8. Spring源码系列 — BeanDefinition扩展点

    前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...

  9. Spring源码系列 — Bean生命周期

    前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...

  10. Spring源码系列(二)--bean组件的源码分析

    简介 spring-bean 组件是 Spring IoC 的核心,我们可以使用它的 beanFactory 来获取所需的对象,对象的实例化.属性装配和初始化等都可以交给 spring 来管理. 本文 ...

随机推荐

  1. Linux系统卡死后紧急处理

    前言:Linux系统卡死了的情况有很多,最常见的是系统负载过高导致的.还可以运行内存耗用极大的程序(如虚拟机),也会迅速提升系统负载.注意:不能再试图依赖任何图形界面的东西,如 Gnome的系统监视器 ...

  2. Day 25 网络基础

    1:网络的重要性: 所有的系统都有网络! 我们的生活已经离不开网络. 运维生涯50%的生产故障都是网络故障! 2:教室这么多的电脑如何上网的? 网卡(mac地址) 有线(双绞线传播电信号)双向,同时收 ...

  3. 删除mac开机启动项

    1、开“系统偏好设置”窗口,选择“用户与群组”,进入用户与群组窗口.选择登录项选项卡,再解锁,最后删除开机启动的应用.   2、分别在以下6个目录中检查是否有与anydesk相关的plist文件 ~/ ...

  4. Jenkins 结合 Docker 为 .NET Core 项目实现低配版的 CI&CD

    随着项目的不断增多,最开始单体项目手动执行 docker build 命令,手动发布项目就不再适用了.一两个项目可能还吃得消,10 多个项目每天让你构建一次还是够呛.即便你的项目少,每次花费在发布上面 ...

  5. Hibernate4之JPA规范配置详解

    @Table Table用来定义entity主表的name,catalog,schema等属性. 属性说明: name:表名 catalog:对应关系数据库中的catalog schema:对应关系数 ...

  6. logback.xml配置文件解析一

    配置文件主要结构如下: <?xml version="1.0" encoding="utf-8"?> <configuration> & ...

  7. selenium--定位--CSS

    大家在使用selenium元素定位的时候,通常更多使用的是XPATH,css定位方式用得比较少 但有时候css定位方式还是有一些优势的, 优势1:一般情况下定位速度要比XPATH快 优势2:语法要比X ...

  8. There is a cycle in the hierarchy解决

    前言: 在一次项目中,分页查询公告列表信息后,在遍历查询到的公告列表时出现了死循环“There is a cycle in the hierarchy”错误,分析原因是因为在公告实体类中包含了商铺对象 ...

  9. 阿里云服务器ecs配置之安装jdk

    一.安装环境 操作系统:Centos 7.4 JDK版本:1.8 工具:Xshell5.Xftp5 二.安装步骤 第一步:下载安装包 (官网)链接: 下载适合自己系统的jdk版本,如图:我下载的是64 ...

  10. Ubuntu 搭建Zookeeper服务

    1.下载安装包 官方下载地址http://apache.fayea.com/zookeeper/ 2.安装 安装前确保系统已安装过JDK,JDK安装过程可参照 2.1 解压下载好的tar.gz安装包到 ...