InstantiationAwareBeanPostProcessor源码分析

InstantiationAwareBeanPostProcessor

一、基本信息

✒️ 作者 - Lex 📝 博客 - 我的CSDN 📚 文章目录 - 所有文章 🔗 源码地址 - InstantiationAwareBeanPostProcessor源码

二、接口描述

InstantiationAwareBeanPostProcessor 提供了在 bean 实例化之前和之后的回调。这意味着我们有机会在实际的目标 bean 实例之前返回一个代理,或者影响 bean 的构造。

三、接口源码

InstantiationAwareBeanPostProcessor 是 Spring 框架自 1.2 版本开始引入的一个核心接口。postProcessBeforeInstantiation:在 bean 实例化之前调用。它允许我们返回 bean 的另一个实例,例如一个代理,这将阻止 Spring 实例化目标 bean。postProcessAfterInstantiation:在 bean 实例化之后但在设置任何属性之前调用。这可用于基于字段的依赖注入或其他自定义初始化任务。postProcessPropertyValues:在 bean 上设置属性值之前调用此方法。它允许我们修改属性,添加新属性,或返回一个完全不同的属性集。

/**
 * 这是 BeanPostProcessor 的子接口,它为 bean 的实例化添加了新的回调方法。
 * 主要是在 bean 实例化之前和之后,但在明确地设置属性或进行自动装配之前。
 *
 * 通常,这个接口用于为特定的目标 beans 抑制默认的实例化。
 * 例如,为了创建带有特殊 `TargetSources` 的代理(如池化的目标、延迟初始化的目标等),
 * 或为了实施其他的注入策略,例如字段注入。
 *
 * 注意:这是一个特殊目的的接口,主要供框架内部使用。
 * 建议尽量实现简单的 BeanPostProcessor 接口,
 * 或从 InstantiationAwareBeanPostProcessorAdapter 继承,
 * 以避免受到这个接口的扩展的影响。
 *
 * @author Juergen Hoeller
 * @author Rod Johnson
 * @since 1.2
 * @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#setCustomTargetSourceCreators
 * @see org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 在目标 bean 被实例化之前应用此 BeanPostProcessor。返回的 bean 对象可能是一个代理,
     * 可用来代替目标 bean,有效地抑制了目标 bean 的默认实例化。
     * 如果此方法返回一个非空对象,bean 的创建过程将被短路。
     * 
     * @param beanClass 要实例化的 bean 的类
     * @param beanName bean 的名称
     * @return 要替代目标 bean 的默认实例公开的 bean 对象,或 {@code null} 继续默认实例化
     * @throws org.springframework.beans.BeansException 如果发生错误
     */
    @Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    /**
     * 在 bean 通过构造函数或工厂方法被实例化后执行操作,但在 Spring 的属性设置(通过明确的属性或自动装配)发生之前。
     * 这是在 Spring 的自动装配开始之前,对给定的 bean 实例执行自定义字段注入的理想回调。
     * 
     * @param bean 已创建的 bean 实例,其属性尚未设置
     * @param beanName bean 的名称
     * @return 如果应该在 bean 上设置属性,则为 {@code true};如果应跳过属性填充,则为 {@code false}。
     * @throws org.springframework.beans.BeansException 如果发生错误
     */
    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    /**
     * 在工厂将它们应用于给定的 bean 之前,对给定的属性值进行后处理,而不需要属性描述符。
     * 
     * @param pvs 工厂即将应用的属性值(永远不为 {@code null})
     * @param bean 已创建但其属性尚未设置的 bean 实例
     * @param beanName bean 的名称
     * @return 要应用于给定 bean 的实际属性值(可以是传入的 PropertyValues 实例),或 {@code null} 
     * @throws org.springframework.beans.BeansException 如果发生错误
     */
    @Nullable
    default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
            throws BeansException {

        return null;
    }

    /**
     * 在工厂将它们应用于给定的 bean 之前,对给定的属性值进行后处理。允许检查所有的依赖关系是否都已满足,
     * 例如基于 bean 属性 setter 上的 "Required" 注解。
     * 
     * @param pvs 工厂即将应用的属性值(永远不为 {@code null})
     * @param pds 目标 bean 的相关属性描述符
     * @param bean 已创建但其属性尚未设置的 bean 实例
     * @param beanName bean 的名称
     * @return 要应用于给定 bean 的实际属性值(可以是传入的 PropertyValues 实例),或 {@code null} 
     * @throws org.springframework.beans.BeansException 如果发生错误
     */
    @Deprecated
    @Nullable
    default PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

        return pvs;
    }
}

四、主要功能

  1. 实例化前的处理

    • 在 bean 实际被实例化之前调用,允许你返回一个代理对象来替代真正的目标 bean,这样你可以避免 bean 的默认实例化过程,这是 AOP 和代理创建中非常有用的一个步骤。
  2. 实例化后的处理

    • 在 bean 实例化后但在属性注入之前调用,这个回调为你提供了在 Spring 自动装配或属性设置之前对 bean 进行自定义处理的机会。
  3. 属性处理

    • 允许你在 Spring 进行属性注入之前对 bean 的属性值进行处理或替换,这是在进行自定义属性注入或验证 bean 属性的理想之处。

五、最佳实践

首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类。然后从Spring上下文中获取一个DataBase类型的bean,最后打印了该bean的几个属性。这样我们就可以确认bean的状态啦。

public class InstantiationAwareBeanPostProcessorApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        DataBase userService = context.getBean(DataBase.class);
        System.out.println("username = " + userService.getUsername());
        System.out.println("password = " + userService.getPassword());
        System.out.println("postInstantiationFlag = " + userService.isPostInstantiationFlag());
    }
}

这里使用@Bean注解,定义了两个Bean,是为了确保DataBaseMyInstantiationAwareBeanPostProcessor 被 Spring 容器执行

@Configuration
public class MyConfiguration {

    @Bean
    public static MyInstantiationAwareBeanPostProcessor myInstantiationAwareBeanPostProcessor() {
        return new MyInstantiationAwareBeanPostProcessor();
    }

    @Bean
    public DataBase dataBase() {
        return new DataBaseImpl();
    }
}

MyInstantiationAwareBeanPostProcessor 的类,该类实现了 Spring 的 InstantiationAwareBeanPostProcessor 接口,在postProcessBeforeInstantiation方法中在DataBase类型的bean开始实例化前,打印一条通知消息,表明我们正在准备实例化该 bean。在postProcessAfterInstantiation方法中DataBase bean实例化后,设置标记属性并通知bean已经实例化。在postProcessProperties:方法中给DataBase bean注入属性前,将密码屏蔽并打印一条消息说明密码已被屏蔽。

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanClass == DataBase.class) {
            System.out.println("正在准备实例化: " + beanName);
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean instanceof DataBase) {
            ((DataBase) bean).setPostInstantiationFlag(true);
            System.out.println("Bean " + beanName + " 已实例化!");
            return true;
        }
        return true;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (bean instanceof DataBase) {
            MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
            mpvs.addPropertyValue("password", "******");
            System.out.println(beanName + "的密码已被屏蔽:");
        }
        return pvs;
    }
}

一个简单的接口定义

public interface DataBase {
    String getUsername();
    void setUsername(String username);
    String getPassword();
    void setPassword(String password);
    boolean isPostInstantiationFlag();
    void setPostInstantiationFlag(boolean flag);
}

使用 @Value 注解在 Spring 的上下文中为相应的属性提供了默认值。

public class DataBaseImpl implements DataBase {

    @Value("root")
    private String username;

    @Value("123456")
    private String password;

    private boolean postInstantiationFlag;
	
    // get and set
}

运行结果发现,dataBase的准备实例化,到已实例化的过程日志打印了,另外最重要的是我们也吧password字段已经被屏蔽了。

正在准备实例化: dataBase
Bean dataBase 已实例化!
dataBase的密码已被屏蔽:
username = root
password = ******
postInstantiationFlag = true

六、时序图

InstantiationAwareBeanPostProcessorApplication AnnotationConfigApplicationContext AbstractApplicationContext DefaultListableBeanFactory AbstractBeanFactory DefaultSingletonBeanRegistry AbstractAutowireCapableBeanFactory MyInstantiationAwareBeanPostProcessor AnnotationConfigApplicationContext 开始初始化 refresh 刷新上下文 finishBeanFactoryInitialization 实例化非懒加载的单列Bean preInstantiateSingletons 预实例化Singleton getBean 根据beanName获取对象 doGetBean 返回指定bean的实例 getSingleton 获取单例对象 getObject ObjectFactory接口的工厂方法 createBean 创建一个bean实例,填充bean实例,应用后处理器 resolveBeforeInstantiation applyBeanPostProcessorsBeforeInstantiation postProcessBeforeInstantiation 实例化前处理 返回Bean对象 如果bean对象不为空直接返回,后续操作跳过 doCreateBean populateBean postProcessAfterInstantiation 实例化后处理 返回true or false 表示属性注入和后续的生命周期处理 postProcessProperties 处理属性 返回Bean对象 返回Bean对象 初始化完成 InstantiationAwareBeanPostProcessorApplication AnnotationConfigApplicationContext AbstractApplicationContext DefaultListableBeanFactory AbstractBeanFactory DefaultSingletonBeanRegistry AbstractAutowireCapableBeanFactory MyInstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor时序图

七、源码分析

首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类。然后通过调用context.getBean(DataBase.class),应用程序从Spring容器中获取了一个名为DataBase的bean实例,并打印了用户名,密码,标志位。

public class InstantiationAwareBeanPostProcessorApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        DataBase userService = context.getBean(DataBase.class);
        System.out.println("username = " + userService.getUsername());
        System.out.println("password = " + userService.getPassword());
        System.out.println("postInstantiationFlag = " + userService.isPostInstantiationFlag());
    }
}

org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext构造函数中,执行了三个步骤,我们重点关注refresh()方法

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}

org.springframework.context.support.AbstractApplicationContext#refresh方法中我们重点关注一下finishBeanFactoryInitialization(beanFactory)这方法会对实例化所有剩余非懒加载的单列Bean对象,其他方法不是本次源码阅读的重点暂时忽略。

@Override
public void refresh() throws BeansException, IllegalStateException {
    // ... [代码部分省略以简化]
    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);
    // ... [代码部分省略以简化]
}

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization方法中,会继续调用DefaultListableBeanFactory类中的preInstantiateSingletons方法来完成所有剩余非懒加载的单列Bean对象。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // ... [代码部分省略以简化]
    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
}

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons方法中,主要的核心目的是预先实例化所有非懒加载的单例bean。在Spring的上下文初始化完成后,该方法会被触发,以确保所有单例bean都被正确地创建并初始化。其中getBean(beanName)是此方法的核心操作。对于容器中定义的每一个单例bean,它都会调用getBean方法,这将触发bean的实例化、初始化及其依赖的注入。如果bean之前没有被创建过,那么这个调用会导致其被实例化和初始化。

public void preInstantiateSingletons() throws BeansException {
    // ... [代码部分省略以简化]
    // 循环遍历所有bean的名称
    for (String beanName : beanNames) {
        getBean(beanName);
    }
    // ... [代码部分省略以简化]
}

org.springframework.beans.factory.support.AbstractBeanFactory#getBean()方法中,又调用了doGetBean方法来实际执行创建Bean的过程,传递给它bean的名称和一些其他默认的参数值。此处,doGetBean负责大部分工作,如查找bean定义、创建bean(如果尚未创建)、处理依赖关系等。

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法中,首先检查所请求的bean是否是一个单例并且已经创建。如果尚未创建,它将创建一个新的实例。在这个过程中,它处理可能的异常情况,如循环引用,并确保返回的bean是正确的类型。这是Spring容器bean生命周期管理的核心部分。

protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {
    // ... [代码部分省略以简化]

    // 开始创建bean实例
    if (mbd.isSingleton()) {
        // 如果bean是单例的,我们会尝试从单例缓存中获取它
        // 如果不存在,则使用lambda创建一个新的实例
        sharedInstance = getSingleton(beanName, () -> {
            try {
                // 尝试创建bean实例
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                // ... [代码部分省略以简化]
            }
        });
        // 对于某些bean(例如FactoryBeans),可能需要进一步处理以获取真正的bean实例
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    // ... [代码部分省略以简化]

    // 确保返回的bean实例与请求的类型匹配
    return adaptBeanInstance(name, beanInstance, requiredType);
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton()方法中,主要负责从单例缓存中获取一个已存在的bean实例,或者使用提供的ObjectFactory创建一个新的实例。这是确保bean在Spring容器中作为单例存在的关键部分。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    // ... [代码部分省略以简化]

    // 同步访问单例对象缓存,确保线程安全
    synchronized (this.singletonObjects) {
        // 从缓存中获取单例对象
        Object singletonObject = this.singletonObjects.get(beanName);

        // 如果缓存中没有找到
        if (singletonObject == null) {
            // ... [代码部分省略以简化]

            try {
                // 使用工厂创建新的单例实例
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // ... [代码部分省略以简化]
            }
            catch (BeanCreationException ex) {
                // ... [代码部分省略以简化]
            }
            finally {
                // ... [代码部分省略以简化]
            }

            // ... [代码部分省略以简化]
        }

        // 返回单例对象
        return singletonObject;
    }
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()方法中,首先尝试调用resolveBeforeInstantiation,这个方法给InstantiationAwareBeanPostProcessor一个机会,允许它们返回一个代理对象,而不是目标bean的实例。如果这一步返回了一个非空的对象(也就是说,一个InstantiationAwareBeanPostProcessor创建了一个代理对象),那么这个代理对象将作为该bean的实例返回,跳过正常的bean创建过程。如果上面的步骤没有返回任何对象,那么代码将执行doCreateBean方法,这个方法负责实际的bean实例化、属性注入和初始化。

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
    
    // ... [代码部分省略以简化]
    
    try {
        // 1. 给BeanPostProcessors一个机会返回一个代理对象,而不是目标bean实例。
        // 如果这步返回了一个非null的bean,那么这个bean将被返回,跳过正常的bean实例化过程。
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        // ... [代码部分省略以简化]
    }

    try {
        // 正常的bean实例化、属性注入和初始化。
        // 2. 这里是真正进行bean创建的部分。
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        // 记录bean成功创建的日志
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // ... [代码部分省略以简化]
    }
    catch (Throwable ex) {
        // ... [代码部分省略以简化]
    }
}

我们来到createBean(beanName,mbd,args)方法中的第一步,在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 方法中,首先尝试在bean实际实例化之前提前完成bean的实例化。这通常是为了返回一个代理对象。applyBeanPostProcessorsBeforeInstantiation 方法,尝试使用 InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation 方法来预先实例化bean。如果上一步成功创建了bean(例如,返回了一个代理对象),那么这个bean还会经过所有注册的 BeanPostProcessorpostProcessAfterInitialization 方法,这是对bean进行初始化后的最后处理。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // 检查是否已尝试在实例化之前解析此bean
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // 如果bean不是合成的,并且存在InstantiationAwareBeanPostProcessors
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            // 确定目标bean的类型
            Class<?> targetType = determineTargetType(beanName, mbd);
            // 如果目标类型不为空
            if (targetType != null) {
                // 尝试在实际实例化之前,通过BeanPostProcessors提前创建bean实例
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                // 如果bean实例创建成功
                if (bean != null) {
                    // 对bean实例应用postProcessAfterInitialization方法
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        // 标记bean在实例化之前是否已被解析
        mbd.beforeInstantiationResolved = (bean != null);
    }
    // 返回创建的bean实例或null
    return bean;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation 方法中,回调每一个InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法。

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
        if (result != null) {
            return result;
        }
    }
    return null;
}

简单的实现InstantiationAwareBeanPostProcessor接口的类MyInstantiationAwareBeanPostProcessor,然后重写了postProcessBeforeInstantiation方法,此方法在bean实例化之前被调用。在bean实例化之前,我们可以选择返回一个不同的bean实例来替换原来要实例化的bean。如果我们从此方法返回非null的对象,Spring将使用我们返回的这个对象作为bean,并不会进入标准的实例化过程。如果返回null,则Spring将继续其正常的bean实例化过程,在postProcessBeforeInstantiation中我们仅是打印一个消息表示正在准备实例化该bean,并返回null。返回null意味着不中断正常的实例化过程。以上就是关于InstantiationAwareBeanPostProcessor类中的postProcessBeforeInstantiation方法的源码分析全过程,剩下两个方法请看后续分析。

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanClass == DataBase.class) {
            System.out.println("正在准备实例化: " + beanName);
        }
        return null;
    }
}

我们来到createBean(beanName,mbd,args)方法中的第二步,在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法中,主要负责两大步骤,第一步是属性注入,第二步是bean初始化,确保bean是完全配置和准备好的。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    // 声明一个对象,后续可能用于存放初始化后的bean或它的代理对象
    Object exposedObject = bean;

    try {
        // 属性注入:这一步将配置中的属性值注入到bean实例中。例如,XML中定义的属性或使用@Autowired和@Value注解的属性都会在这里被注入
        populateBean(beanName, mbd, instanceWrapper);

        // bean初始化:这一步会执行bean的初始化方法,同时也会调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,它们可以对bean进行进一步的处理
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } 
    catch (Throwable ex) {
        // ... [代码部分省略以简化]
    }

    // 返回创建和初始化后的bean
    return exposedObject;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法中,首先会调用所有的InstantiationAwareBeanPostProcessorspostProcessAfterInstantiation方法,以给它们一个机会在属性设置之前修改bean的状态。如果postProcessAfterInstantiation方法返回的是true,它首先会尝试使用postProcessProperties方法来处理属性值。如果这个方法返回null,则会继续使用老版本的postProcessPropertyValues方法。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // ... [代码部分省略以简化]

    // 如果当前的Bean不是合成的,并且存在InstantiationAwareBeanPostProcessors,那么给这些后处理器一个机会
    // 在Spring填充属性之前进行处理,例如支持不同风格的字段注入。
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            // 如果返回false,代表此bean的属性不应继续被填充。
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    // ... [代码部分省略以简化]
    // 对每一个InstantiationAwareBeanPostProcessor进行处理,这些处理器可能会修改Bean的属性值。
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        // 尝试使用新版本的方法 postProcessProperties
        PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        if (pvsToUse == null) {
            // 如果postProcessProperties返回null,尝试使用旧版本的方法 postProcessPropertyValues
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            // 如果旧版本的方法也返回null,那么此bean的属性不应继续被填充。
            if (pvsToUse == null) {
                return;
            }
        }
        pvs = pvsToUse;
    }
    // ... [代码部分省略以简化]
}

最后调用到我们自定义的实现逻辑中来,在postProcessAfterInstantiation方法中设置了bean的postInstantiationFlag属性为true。这可以视为我们留下的标记,说明该bean已经被实例化了,然后返回true,表示我们允许Spring继续bean的初始化。然后再postProcessProperties方法中,修改bean的属性值将password属性的值修改为"******"

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean instanceof DataBase) {
            ((DataBase) bean).setPostInstantiationFlag(true);
            System.out.println("Bean " + beanName + " 已实例化!");
            return true;
        }
        return true;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (bean instanceof DataBase) {
            MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
            mpvs.addPropertyValue("password", "******");
            System.out.println(beanName + "的密码已被屏蔽:");
        }
        return pvs;
    }
}

八、注意事项

  1. 影响性能

    • 这种后置处理器会在每个bean的创建过程中调用多次。尽量确保后处理器的逻辑简单且执行速度快,以减少对应用性能的影响。如果你在这三个方法postProcessBeforeInstantiationpostProcessAfterInstantiationpostProcessProperties中执行了复杂的逻辑,如数据库查询、远程调用或其他IO操作,由于每个bean的创建都会触发后处理器,这意味着上述方法将被频繁调用,这会严重影响应用启动时间和bean的创建性能。
  2. 返回非空的bean

    • 如果在postProcessBeforeInstantiation方法中返回了非空的bean,那么正常的bean实例化和属性设置流程将被短路。这意味着postProcessAfterInstantiationpostProcessProperties等方法将不会被调用。另外也会导致BeanPostProcessor类中的postProcessBeforeInitialization也不会被调用
  3. 避免修改非目标bean

    • 如果我们的InstantiationAwareBeanPostProcessor只对特定类型或名称的bean进行操作,确保在执行任何操作之前进行适当的检查。

九、总结

最佳实践总结
  1. 启动与上下文初始化:

    • 使用AnnotationConfigApplicationContext来启动应用,并注册了配置类MyConfiguration

    • 从Spring上下文中获取了一个DataBase类型的bean并打印了它的属性,这是为了验证bean状态的更改是否成功。

  2. 配置类与Bean定义:

    • 通过MyConfiguration配置类,两个Bean(DataBaseMyInstantiationAwareBeanPostProcessor)被定义。其中MyInstantiationAwareBeanPostProcessor是一个后处理器,它会在Spring容器中的其他Bean实例化时触发。
  3. 拦截实例化过程:

    • MyInstantiationAwareBeanPostProcessor类实现了Spring的InstantiationAwareBeanPostProcessor接口,这允许它介入bean的实例化、初始化和属性设置过程。

    • postProcessBeforeInstantiation方法中,当DataBase bean开始实例化之前,一个通知消息被打印。

    • postProcessAfterInstantiation方法中,bean已经实例化,此时会设置一个标记属性并打印一条通知消息。

    • postProcessProperties方法中,修改了DataBase bean的密码属性,并打印了通知消息。

  4. DataBase接口与实现:

    • 定义了一个DataBase接口,该接口定义了数据库连接的基本属性及其getters和setters。

    • DataBaseImpl类中,实现了这个接口,并使用@Value注解为属性设置了默认值。

  5. 运行结果:

    • 从输出中可以看到,dataBase bean从准备实例化到实例化的过程都被成功拦截,并且密码已经被屏蔽。
源码分析总结
  1. 启动及Bean获取

    • 应用程序启动时,AnnotationConfigApplicationContext类被用于初始化Spring上下文,并注册了配置类MyConfiguration

    • 然后,应用程序从Spring上下文中获取名为DataBase的bean实例并打印它的一些属性。

  2. 注册Bean及后处理器

    • 通过MyConfiguration配置类,注册了两个Bean,其中一个是MyInstantiationAwareBeanPostProcessor,这个后处理器用于在Bean实例化过程中介入。
  3. 实例化前的拦截

    • 在Bean实例化之前,Spring首先调用postProcessBeforeInstantiation方法。这里,我们只是简单地打印了一条消息并返回了null,表示让Spring继续执行标准的Bean实例化。
  4. Bean属性注入

    • 在Bean实例化之后但属性注入之前,Spring调用postProcessProperties方法。

    • 在这个示例中,我们修改了password属性的值为"******"并打印了一条消息。

  5. Bean实例化后的处理

    • 紧接着,postProcessAfterInstantiation方法被调用。这里,我们简单地设置了postInstantiationFlag属性并打印了一条消息。
  6. Bean的完成

    • 在所有这些拦截器运行后,Spring会继续进行属性注入、Bean初始化等后续工作。

    • 之后,Bean将完全初始化并准备好供应用程序使用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值