Spring 之 InstantiationAwareBeanPostProcessor 接口

Spring 之 InstantiationAwareBeanPostProcessor 接口

 

 

1、简介

InstantiationAwareBeanPostProcessor 接口是 BeanPostProcessor 的子接口,通过接口字面意思翻译该接口的作用是对 Bean实例化的处理器。

接口源码如下:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * bean 实例化之前钩子
     */
    @Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    /**
     * bean 实例化之后的钩子
     */
    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    /**
     * bean 实例化之后 且postProcessAfterInstantiation返回true 执行bean的属性操作的钩子
     */
    @Nullable
    default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
            throws BeansException {

        return null;
    }
}

java项目ProcessBuilder的脚本地址在java项目里如何运行_ide

 

2、使用示例:

2.1、创建接口实现类 MyInstantiationAwareBeanPostProcessor

/**
 * @Author dw
 * @ClassName MyInstantiationAwareBeanPostProcessor
 * @Description
 * @Date 2021/12/11 21:16
 * @Version 1.0
 */
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    /**
     * InstantiationAwareBeanPostProcessor中自定义的方法
     * 在方法实例化之前执行  Bean对象还没有
     * 如果不需要对实例化之前的bean进行替换,可以返回null
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInstantiation..." + beanName);
        return null;
    }
    /**
     * InstantiationAwareBeanPostProcessor中自定义的方法
     * 在方法实例化之后执行  Bean对象已经创建出来了
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInstantiation..." + beanName);
        return true;
    }
    /**
     * InstantiationAwareBeanPostProcessor中自定义的方法
     * 可以用来修改Bean中属性的内容
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("postProcessProperties..."  + beanName);
        return pvs;
    }
    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定义初始化方法之前执行
     * Bean对象已经存在了,不能返回null, 否则会报NullPointerException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..." + beanName);
        return bean;
    }
    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定义初始化方法执行完成之后执行
     * Bean对象已经存在了,不能返回null, 否则会报NullPointerException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization..." + beanName);
        return bean;
    }
}

 

2.2:创建bean : MyUser

@Data
public class MyUser  {
    private String userName;
    private Integer userAge;
    private UserRole userRole;
}
@Configuration
public class MyBeanConfig {
    @Bean
    public MyUser myUser(){
        return new MyUser();
    }
}

启动项目发现控制台会打印一堆的如下输出, 说明实现了该接口后, 对容器中的大部分 bean 都有效。

postProcessBeforeInstantiation...myUser
postProcessAfterInstantiation...myUser
postProcessProperties...myUser
postProcessBeforeInitialization...myUser
postProcessAfterInitialization...myUser

 

3、分析相关方法

3.1、postProcessBeforeInstantiation

该方法返回的结果如果为null,后面的方法都正常执行了,但是如果该方法返回了实例对象了呢?我们来看下

修改 postProcessBeforeInstantiation: 

@Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInstantiation...");
        if (beanName.equals("myUser")) {
            return new MyUser();
        }
        return null;
    }

控制台输出如下:

postProcessBeforeInstantiation...myUser
postProcessAfterInitialization...myUser

通过数据结果我们发现,postProcessBeforeInstantiation方法返回实例对象后跳过了对象的初始化操作,直接执行了postProcessAfterInitialization,跳过了postProcessAfterInstantiation,postProcessPropertyValues,为什么会这样呢?我们要来查看下源代码。
在AbstractAutowireCapableBeanFactory类中有个createBean方法:

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;
        }
       // ... 省略
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

4、总结:

   如果postProcessBeforeInstantiation方法返回了Object是null;  那么就直接调用doCreateBean方法();
   如果postProcessBeforeInstantiation返回不为null;说明修改了bean对象;然后这个时候就立马执行postProcessAfterInitialization方法(注意这个是初始化之后的方法,也就是通过这个方法实例化了之后,直接执行初始化之后的方法;中间的实例化之后 和 初始化之前都不执行);
个人觉得这个接口只有这个方法 postProcessBeforeInstantiation 有点用, 其余两个方法并没有啥用。SpringAop的实现就是基于InstantiationAwareBeanPostProcessor 的postProcessBeforeInstantiation 这个方法使用代理替换了原有的对象实例。

 

5、InstantiationAwareBeanPostProcessor 执行流程、时机分析

org.springframework.context.support.AbstractApplicationContext#refresh

java项目ProcessBuilder的脚本地址在java项目里如何运行_spring_02

 org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

java项目ProcessBuilder的脚本地址在java项目里如何运行_spring_03

 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

java项目ProcessBuilder的脚本地址在java项目里如何运行_ide_04

 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

java项目ProcessBuilder的脚本地址在java项目里如何运行_ide_05

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

java项目ProcessBuilder的脚本地址在java项目里如何运行_spring_06

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

java项目ProcessBuilder的脚本地址在java项目里如何运行_实例化_07

 回到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean 如果 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 没有返回代理对象实例,则走普通Bean的创建逻辑。

java项目ProcessBuilder的脚本地址在java项目里如何运行_ide_08

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

java项目ProcessBuilder的脚本地址在java项目里如何运行_实例化_09

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

java项目ProcessBuilder的脚本地址在java项目里如何运行_ide_10