10.BeanFactoryPostProcessor

129 阅读6分钟

BeanFactoryPostProcessor

前几篇我们详细讲解了BeanDefinition的源码,我们知道spring扫描符合规则的业务类后会通过 AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner将业务类封装成BeanDefinition保存在IOC容器中,那么,spring容器启动过程中是在哪里扫描的呢?

答案是在BeanFactoryPostProcessor后置处理器中完成扫描功能,不仅仅是类扫描,BeanFactoryPostProcessor能完成更丰富的功能,比如bean拦截处理、spring扩展开发都离不开它。

从本篇文章开始,笔者将向大家详细阐述BeanFactoryPostProcessor。

BeanFactoryPostProcessor分两种,一种是spring内置,一种由程序员提供。

我们首先通过注解的方式启动spring:

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(Config.class);
        context.refresh();

context.refresh()完成了spring的启动过程,类扫描也是在这个方法中完成的,这个方法的实现是在AnnotationConfigApplicationContext的父类AbstractApplicationContext方法中完成的。

跳转到具体的实现,找到下面这行源码:

    invokeBeanFactoryPostProcessors(beanFactory);

这行代码的逻辑:先执行已经注册到bean工厂中的所有内置BeanFactoryPostProcessor,再执行程序员提供的BeanFactoryPostProcessor。

BeanFactoryPostProcessor

BeanFactoryPostProcessor是bean工厂的后置处理器,能干预bean工厂的工作流程。

那么什么又是bean工厂呢?

AnnotationConfigApplicationContext context 
                        = new AnnotationConfigApplicationContext();

这行代码首先会执行无参构造函数,学过java的读者都知道,无参构造函数在调用前先调用父类的构造函数,AnnotationConfigApplicationContext的父类是GenericApplicationContext:

public class AnnotationConfigApplicationContext extends         
       GenericApplicationContext implements AnnotationConfigRegistry 

我们看下GenericApplicationContext无参构造函数:

private final DefaultListableBeanFactory beanFactory;

public GenericApplicationContext() {
    //实例化bean工厂
    this.beanFactory = new DefaultListableBeanFactory();
}

DefaultListableBeanFactory就是bean工厂,在BeanDefinition我们讲过spring生成的BeanDefinition会保存在一个map当中,这个map就是保存在DefaultListableBeanFactory的beanDefinitionMap当中:

//DefaultListableBeanFactory中的属性beanDefinitionMap,用于保存BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap 
                                            = new ConcurrentHashMap<>(256);

BeanFactoryPostProcessor是一个接口,它只定义了一个方法postProcessBeanFactory,spring启动过程中会自动回调BeanFactoryPostProcessor的实现类的postProcessBeanFactory方法。

postProcessBeanFactory方法有一个ConfigurableListableBeanFactory的类型参数beanFactory,也就是说我们可以在这个postProcessBeanFactory方法里操作bean工厂。

BeanFactoryPostProcessor是spring扩展开发的根本,专业讲是Spring初始化bean时对外暴露的扩展点。

    @FunctionalInterface
    public interface BeanFactoryPostProcessor {
      void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
    }

Spring IoC容器允许BeanFactoryPostProcessor在容器实例化任何bean之前读取bean的定义,并可以修改它。

同时可以定义多个BeanFactoryPostProcessor,通过设置order属性来确定BeanFactoryPostProcessor执行顺序。

注册一个BeanFactoryPostProcessor实例需要定义一个Java类来实现BeanFactoryPostProcessor接口,并重写该接口的postProcessorBeanFactory方法,spring启动过程中会自动调用我们的后置处理器:

    @Component
    public class CZZBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("自己定义的后置处理器,在这里我可以拿到bean工厂");
        }
    }
    
    public class SpringTest {
        public static void main(String[] args) throws InterruptedException {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            //注册配置类
            context.register(Config.class);
            //加载或者刷新当前的配置信息
            context.refresh();
        }
    }

image.png

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口

也就是BeanFactoryPostProcessor继承了BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
       void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
   }

该接口只定义一个postProcessBeanDefinitionRegistry方法,且传入的参数类型是BeanDefinitionRegistry,这是遵循了7大软件设计原则中的迪米特法则即最小知识法则。

    DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
            implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable 

spring真正的bean工厂是DefaultListableBeanFactory,而ConfigurableListableBeanFactory和BeanDefinitionRegistry都是DefaultListableBeanFactory的上层接口即父接口。

传入BeanDefinitionRegistry或者ConfigurableListableBeanFactory缩小了传入参数可访问的方法,换句话讲降低了你的权限,如果spring回调你的方法给你传入一个DefaultListableBeanFactory类型的参数,那么你将得到整个bean工厂的权限,那太危险了,我给你传入指定接口类型的bean工厂参数,你只能调用指定接口中的方法,降低你的权限保证spring的安全。

类似于linux上的root用户和普通用户,你得到我的root账号破坏我系统那就不好了。

BeanDefinitionRegistryPostProcessor调用顺序

PriorityOrdered:数字越小优先级越高

spring有内置的BeanFactoryPostProcessor,程序员也可以自定义BeanFactoryPostProcessor。

spring是先调用内置的BeanFactoryPostProcessor 再调用程序员自定义的BeanFactoryPostProcessor。

sping是怎样做到的呢?

答案就是通过invokeBeanFactoryPostProcessors来实现。

源码调用链:refresh -> invokeBeanFactoryPostProcessors -> invokeBeanFactoryPostProcessors


protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   //核心代码
   //注意这里也传入了1个BeanFactoryPostProcessor集合
   //其中的BeanFactoryPostProcessor是通过getBeanFactoryPostProcessors()拿到的
   //并且做了一些处理
   PostProcessorRegistrationDelegate
                 .invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}

在invokeBeanFactoryPostProcessors方法中找到下面的代码


    /*** 省略调用通过getBeanFactoryPostProcessors()获取到的List<BeanFactoryPostProcessor> ***/


    //根据类型查询BeanDefinitionRegistryPostProcessor的名称,注意获取的只是name
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType
            (BeanDefinitionRegistryPostProcessor.class, true, false);
            
    //遍历所有BeanDefinitionRegistryPostProcessor的实现类的名称       
    for (String ppName : postProcessorNames) {
        //判断BeanDefinitionRegistryPostProcessor是否实现了PriorityOrdered接口
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            //实现了PriorityOrdered接口添加到数组中,后续进行遍历执行
            currentRegistryProcessors
                .add(beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class))        
            //存储BeanDefinitionRegistryPostProcessor实现类的名字
            processedBeans.add(ppName);
        }
    }
    
    //对BeanDefinitionRegistryPostProcessor设置调用顺序
    sortPostProcessors(currentRegistryProcessors, beanFactory);
    registryProcessors.addAll(currentRegistryProcessors);
    
    //执行BeanDefinitionRegistryPostProcessor
    invokeBeanDefinitionRegistryPostProcessors
                    (currentRegistryProcessors, registry);

上面代码的大体意思是,先查询容器中实现PriorityOrdered接口的内置BeanDefinitionRegistryPostProcessor后置处理器并保存到数组中,然后对处理器进行排序,紧接着就调用BeanDefinitionRegistryPostProcessor处理器。

如果你跟着笔者的思路进行调试的话,会发现此时spring中只有一个BeanDefinitionRegistryPostProcessor类型的后置处理器,就是ConfigurationClassPostProcessor。

另外还有1个问题,我们拿到的不是BeanDefinitionRegistryPostProcessor的名称吗?

怎么突然就能作为BeanDefinitionRegistryPostProcessor被执行了呢?

关键代码在这一句:

currentRegistryProcessors.add(beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class))

beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class)

getBean方法会开启bean的生命周期,完成bean的实例化和初始化。

image.png

//public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor 
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
                  PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware{
}
    //这里的getOrder方法是PriorityOrdered接口的方法
    //PriorityOrdered接口继承了Ordered接口

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

虽然ConfigurationClassPostProcessor只实现了BeanDefinitionRegistryPostProcessor接口,但是BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口。

所以ConfigurationClassPostProcessor既实现了BeanDefinitionRegistryPostProcessor又实现了BeanFactoryPostProcessor。

ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    
    //每个BeanDefinitionRegistry都有自己的唯一标识,不能被重复调用否则抛出异常。
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
                "postProcessBeanDefinitionRegistry already called " + registry);
    }
    
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called " + registry);
    }
    this.registriesPostProcessed.add(registryId);
    //处理配置类的bean定义信息
    processConfigBeanDefinitions(registry);
}

BeanDefinitionRegistry的主要功能是参与BeanFactory的BeanDefinition的扫描与注册。准备来说 ConfigurationClassPostProcessor作为BeanDefinitionRegistry的主要功能是参与BeanFactory的BeanDefinition的扫描与注册。

在ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import @ImportSelector @Bean @PropertySource @ImportSource等注解。

总之爸爸级别的存在,极其的重要!!!后面会详细详细再详细的讲清楚!

Ordered:数字越小优先级越高

上面是找到了实现了PriorityOrdered接口的BeanDefinitionRegistry 我们接着上面的invokeBeanFactoryPostProcessors源码继续看:

//此时ConfigurationClassPostProcessor完成了扫描
//也就是说程序员自定义的后置处理器已经被扫描到
//此时可以查询程序员提供的BeanDefinitionRegistryPostProcessor后置处理器并执行!
//继续查询BeanDefinitionRegistryPostProcessor类型的名称
postProcessorNames = beanFactory.getBeanNamesForType
                                    (BeanDefinitionRegistryPostProcessor.class, true, false);
//遍历BeanDefinitionRegistryPostProcessor类型的名称
for (String ppName : postProcessorNames) {
    //如果实现了Ordered接口且没有被调用过
    if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName,            
                                        BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}

//设置调用顺序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);

//调用程序员提供的后置处理器
invokeBeanDefinitionRegistryPostProcessors
                            (currentRegistryProcessors, registry);

currentRegistryProcessors.clear();

spring内置的BeanDefinitionRegistryPostProcessor调用之后,spring继续调用实现了Ordered接口的BeanDefinitionRegistryPostProcessor后置处理器,因为此时spring已经完成了扫描加载,所以此时后置处理器既包括spring内置的也包括程序员提供的,我们提供一个BeanDefinitionRegistryPostProcessor后置处理器:

@Component
public class MyBeanFactoryReigtryPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("调用MyBeanFactoryReigtryPostProcessor1");
    }
    //数字越小优先级越高
    @Override
    public int getOrder() {
        return 1;
    }
}

@Component
public class MyBeanFactoryReigtryPostProcessor2 implements BeanDefinitionRegistryPostProcessor, Ordered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("调用MyBeanFactoryReigtryPostProcessor2");
    }
    //数字越小优先级越高
    @Override
    public int getOrder() {
        return 2;
    }
}

image.png

不带PriorityOrdered和Ordered

最后,spring调用没有实现Ordered接口和PriorityOrdered接口的BeanDefinitionRegistryPostProcessor后置处理器。包括spring内置的和程序员提供的:

@Component
public class MyBeanFactoryReigtryPostProcessor3 implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory 
                                       beanFactory)throws BeansException {
    }
    @Override
    public void postProcessBeanDefinitionRegistry
                (BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("调用MyBeanFactoryReigtryPostProcessor3");
    }
}

image.png

总结一下先调用spring内置的实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor后置处理器,只有ConfigurationClassPostProcessor。

再调用实现Ordered接口的BeanDefinitionRegistryPostProcessor后置处理器,包括内置和自定义的。

最后调用剩下的所有BeanDefinitionRegistryPostProcessor后置处理器。

BeanFactoryPostProcessor调用顺序

调用完后继续看源码:invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

还记得BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor吗?

其实上面spring调用的是BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,而这行代码调用的是父接口BeanFactoryPostProcessor中的postProcessBeanFactory方法。

调用完BeanDefinitionRegistryPostProcessor紧接着调用BeanFactoryPostProcessor后置处理器。

//查询实现BeanFactoryPostProcessor接口的后置处理器
String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
        
//实现PriorityOrdered接口的BeanFactoryPostProcessor集合
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();

//实现Ordered接口的BeanFactoryPostProcessor集合
List<String> orderedPostProcessorNames = new ArrayList<>();

//啥也没实现的BeanFactoryPostProcessor集合
List<String> nonOrderedPostProcessorNames = new ArrayList<>();

// 首先调用实现PriorityOrdered接口的BeanFactoryPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

// 接着调用实现Ordered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
    orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

// 最后调剩下所有的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
    nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// 清除元数据缓存
beanFactory.clearMetadataCache();

spring首先调用实现PriorityOrdered接口的BeanFactoryPostProcessor。

接着调用实现Ordered接口的BeanFactoryPostProcessor。

最后调剩下所有的BeanFactoryPostProcessor。

以上,我们初探了后置处理器的概念及调用过程。后续我们将深入分析后置处理器。