10.BeanFactoryPostProcessor


highlight: arduino-light

BeanFactoryPostProcessor

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

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

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

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

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

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

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

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

java invokeBeanFactoryPostProcessors(beanFactory);

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

BeanFactoryPostProcessor

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

那么什么又是bean工厂呢?

java AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

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

java public class AnnotationConfigApplicationContext extends       GenericApplicationContext implements AnnotationConfigRegistry

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

```java private final DefaultListableBeanFactory beanFactory;

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

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

java //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时对外暴露的扩展点。

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

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

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

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

```java @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

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

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

java 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

```java

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

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

```java

/*** 省略调用通过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

java //public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware{ }

```java //这里的getOrder方法是PriorityOrdered接口的方法 //PriorityOrdered接口继承了Ordered接口

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

```

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

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

ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

```java @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源码继续看:

```java //此时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后置处理器: ```java @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内置的和程序员提供的: java @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后置处理器。

```java //查询实现BeanFactoryPostProcessor接口的后置处理器 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

//实现PriorityOrdered接口的BeanFactoryPostProcessor集合 List priorityOrderedPostProcessors = new ArrayList<>();

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

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

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

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

// 最后调剩下所有的BeanFactoryPostProcessor List 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。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BeanFactoryPostProcessorSpring 框架中的一个接口,它允许我们在 Spring 容器加载 Bean 定义之后,但在实例化 Bean 之前对 Bean 的定义进行修改或者添加一些自定义逻辑。 在面试过程中,面试官可能会问到关于 BeanFactoryPostProcessor 的相关问题,下面是一些常见的问题及其答案: 1. BeanFactoryPostProcessorBeanPostProcessor 的区别是什么? - BeanFactoryPostProcessor 是在 Spring 容器加载 Bean 定义之后调用的,用于对 Bean 的定义进行修改。 - BeanPostProcessor 是在 Spring 容器创建完 Bean 实例之后,但在初始化之前调用的,用于对 Bean 进行加工处理。 2. BeanFactoryPostProcessor 的作用是什么? - 可以用于修改或增强 Bean 的定义,例如修改属性值、添加属性、更改 Bean 的作用域等。 - 可以实现一些自定义的逻辑,例如动态注入依赖、注册额外的 Bean 等。 3. BeanFactoryPostProcessor 的执行时机是什么? - BeanFactoryPostProcessorSpring 容器加载完 Bean 定义之后,但在实例化 Bean 之前执行。 - 在执行 BeanFactoryPostProcessor 期间,可以对 Bean 的定义进行任何修改,这些修改将应用于后续的 Bean 实例化过程。 4. 如何使用 BeanFactoryPostProcessor? - 创建一个实现了 BeanFactoryPostProcessor 接口的类,并实现其 postProcessBeanFactory() 方法。 - 在 Spring 配置文件中配置该 BeanFactoryPostProcessor 的实现类。 以上是关于 BeanFactoryPostProcessor 的一些常见问题,希望对你有帮助!如果你还有其他问题,可以继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值