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();
}
}
```
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的实例化和初始化。
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;
}
} ```
不带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"); } }
总结一下先调用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。
以上,我们初探了后置处理器的概念及调用过程。后续我们将深入分析后置处理器。