Bootstrap

Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor

BeanFactoryPostProcessor和BeanPostProcessor这两个接口都是初始化bean时对外暴露的入口之一,和Aware类似(PS:关于spring的hook可以看看Spring钩子方法和钩子接口的使用详解讲的蛮详细)本文也主要是学习具体的钩子的细节,以便于实际开发中我们能有效率,例如如何在scala中如何获取springboot的启动类等等,一些中间件为了监控整个系统的服务,也需要获取到spring容器数据和状态。
接下来具体学习和了解下BeanFactoryPostProcessor和BeanPostProcessor。

BeanFactoryPostProcessor
bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。

使用方法

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    /**
     * 主要是用来自定义修改持有的bean
     * ConfigurableListableBeanFactory 其实就是DefaultListableBeanDefinition对象
     * @param beanFactory
     * @throws BeansException
     */

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用了自定义的BeanFactoryPostProcessor " + beanFactory);
        Iterator it = beanFactory.getBeanNamesIterator();

        String[] names = beanFactory.getBeanDefinitionNames();
        // 获取了所有的bean名称列表
        for(int i=0; i<names.length; i++){
            String name = names[i];

            BeanDefinition bd = beanFactory.getBeanDefinition(name);
            System.out.println(name + " bean properties: " + bd.getPropertyValues().toString());
            // 本内容只是个demo,打印持有的bean的属性情况
        }
    }
}
<context:property-placeholder location="pro.properties" />
<bean id="student" class="Student" init-method="init" />
<bean class="CustomBeanFactoryPostProcessor" id="customBeanFactoryPostProcessor" />

输出结果

在这里插入图片描述

源码分析

毫无疑问肯定已经解析xml了,继续看refresh函数

AbstractApplicationContext 文件

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // 解析xml完成,存储在一个具体的bean工厂中
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // bean工厂的初始化操作
        prepareBeanFactory(beanFactory);
        try {
            // 由子类继承去实现该类,当前该方法为空
            postProcessBeanFactory(beanFactory);
            // invoke 其中存在的BeanFactoryPostProcessors,也就是我们现在说的
            invokeBeanFactoryPostProcessors(beanFactory);
        ...

PostProcessorRegistrationDelegate 文件

invokeBeanFactoryPostProcessors方法的参数为bean工厂ConfigurableListableBeanFactory和当前已知的postprocessor对象,函数分为了好几部分去处理,截取其中我们关心的部分即可(其实还包含了优先级、属性等类似处理过程)

String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
        // 筛选出bean工程中存在的所有实现BeanFactoryPostProcessor类的类名称

        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
        List<String> orderedPostProcessorNames = new ArrayList<String>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // 已经存在了,不再处理
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
                // 为PriorityOrdered类型
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
                // 为Ordered类型
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
                // 这个就是我们当前需要关心的PostProcessors
            }
        }

        ...
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
            // 获取自定义的BeanFactoryPostProcessor
            // 这里有一点需要注意到!!!!
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

上述代码中nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));中使用了getBean,起初没注意到以为是生成具体的对象然后修改,其实不是,getBean后面还有一个参数BeanFactoryPostProcessor.class,注意看这个函数,会发现返回的是一个抽象类,结论就是nonOrderedPostProcessors添加的不是bean实例,而是beandefinition,在实例化前!!!,这点很重要

private static void invokeBeanFactoryPostProcessors(
        Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    for (BeanFactoryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanFactory(beanFactory);
        // 调用每一个自定义的BeanFactoryPostProcessor的方法
        // 在本文章中就会去调用自定义的CustomBeanFactoryPostProcessor的postProcessBeanFactory方法
    }
}

再多说一点关于上面的getBeanNamesForType函数,从名字肯定很容易理解了,根据传递的类型获取容器中的beanName。了解下其内部的实现原理

DefaultListableBeanFactory 文件的 getBeanNamesForType函数

// type:类的类型名称
// includeNonSingletons:返回数据包含了非单例beanName
// allowEagerInit: 可以提前加载初始化
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
    if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
       // 不可用缓存、类型无效、不允许提前加载初始化
       // 需要获取当前type的原始类型,继续获取数据
        return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
    }
    Map<Class<?>, String[]> cache =
            (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
    String[] resolvedBeanNames = cache.get(type);
    // 如果缓存已经存储了该数据,则无需再计算,直接返回即可
    if (resolvedBeanNames != null) {
        return resolvedBeanNames;
    }
    resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
    // 这一步就是真正的获取数据,遍历beanDefinitionNames的每一个数据,符合要求的就会加入到返回的列表中
    
    if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
        cache.put(type, resolvedBeanNames);
        // 便于下一次获取,加入缓存中
    }
    return resolvedBeanNames;
}

BeanPostProcessor
从范围上来说,从上面的所有的bean成为了特定的bean,其次BeanFactoryPostProcessor可以在初始化前修改bean的属性等情况,但是BeanPostProcessor只能在初始化后(注意初始化不包括init方法)执行一些操作。
网上很多文章都说BeanPostProcessor不能修改bean属性,其实我看来未必,当其实例化之后,完全可以拿到实例化后的对象,对对象进行一些改值操作也完全可以的

使用方法

public class Student {

    @Value("${name}")
    private String className;

    public Student() {
        System.out.println("constructor loading");
    }

    public void init(){
        System.out.println("init loading");
    }
}
public class CustomBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Student){
            // 如果当前的bean是Student,则打印日志
            System.out.println("postProcessBeforeInitialization bean : " + beanName);
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Student){
            System.out.println("postProcessAfterInitialization bean : " + beanName);
        }
        return bean;
    }
}
<bean id="student" class="Student" init-method="init" />
<bean class="CustomBeanPostProcessor" id="customBeanPostProcessor" />

输出结果

在这里插入图片描述
先打印出了构造器内部执行的话,意味着这个时候实例化了Student类,
在init方法前执行了postProcessBeforeInitialization
在init方法后执行了postProcessAfterInitialization
源码分析
入口依旧是refresh函数,在完成初始化之后,进入到finishBeanFactoryInitialization(beanFactory)执行BeanPostProcessor的相关操作,中间的流程过长,包含了getBean操作,genBean操作过于繁琐,后续再介绍。

在这里插入图片描述
AbstractAutowireCapableBeanFactory 文件

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
        // aware同样是对外提供的钩子
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        // 这一步就是执行自定义的beanpostprocessor的before操作
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
        // 执行init方法
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        // 这一步就是执行自定义的beanpostprocessor的after操作
    }
    return wrappedBean;
}
public Object applyBeanPostProcessorsBeforeInitialization(
                    Object existingBean, String beanName)
        throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
       // 获取所有的BeanPostProcessor对象,执行postProcessBeforeInitialization方法
        result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
    // 然后把执行结果返回
}
public Object applyBeanPostProcessorsAfterInitialization(
                Object existingBean, String beanName)
        throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}
protected void invokeInitMethods(String beanName, 
                    final Object bean, RootBeanDefinition mbd)
        throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null) {
       // invoke 反射执行init方法
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;