前几篇博文我们详细讲解了BeanDefinition的源码,我们知道spring扫描符合规则的业务类后会将业务类封装成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方法中完成的,单击该行代码跳转到具体的实现,找到下面这行源码:
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
这样代码的意思是,先执行已经注册到bean工厂中的所有内置BeanFactoryPostProcessor,再执行程序员提供的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当中:
//DefaultListableBeanFactory源码中的beanDefinitionMap 变量,用于保存BeanDefinition
private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
BeanFactoryPostProcessor 是一个接口,它只定义了一个方法postProcessBeanFactory
,spring启动过程中会自动回调BeanFactoryPostProcessor 的实现类的postProcessBeanFactory
方法,这个方法有一个ConfigurableListableBeanFactory 的类型参数beanFactory,也就是说我们可以在这个postProcessBeanFactory
方法里操作bean工厂,bean工厂何许人也,那岂不是肆意妄为!相当于我们控制住了敌人的兵工厂。这也是spring扩展开发的根本,专业讲是Spring初始化bean时对外暴露的扩展点。
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
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();
}
}
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor有个子接口BeanDefinitionRegistryPostProcessor
:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
该接口只定义一个postProcessBeanDefinitionRegistry
方法,且传入的参数类型是BeanDefinitionRegistry,如果你读过上一篇bean工厂的博文就该知道这是遵循了7大软件设计原则中的迪米特法则。怎么讲?spring真正的bean工厂是DefaultListableBeanFactory,而ConfigurableListableBeanFactory
和BeanDefinitionRegistry
都是DefaultListableBeanFactory的上层接口,缩小了传入参数可访问的方法,换句话讲降低了你的权限,如果spring回调你的方法给你传入一个DefaultListableBeanFactory类型的参数,那么你将得到整个bean工厂的权限,那太危险了,我给你传入指定接口类型的bean工厂参数,你只能调用指定接口中的方法,降低你的权限保证spring的安全。类似于linux上的root用户和普通用户,你得到我的root账号破坏我系统那就不好了。
后置处理器调用顺序
spring有内置的BeanFactoryPostProcessor,程序员也可以自定义BeanFactoryPostProcessor,spring是先调用内置的BeanFactoryPostProcessor 再调用程序员自定义的BeanFactoryPostProcessor ,sping是怎样做到的呢?
答案就是通过BeanDefinitionRegistryPostProcessor
来实现。我们看下源码,refresh -> invokeBeanFactoryPostProcessors -> invokeBeanFactoryPostProcessors
:
.......省略.......
//查询BeanDefinitionRegistryPostProcessor的实现类
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//添加到数组中,后续进行遍历回调
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
:
它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了
@Configuration
的配置类,还会解析@ComponentScan
、@ComponentScans
注解扫描的包,以及解析@Import
等注解。总之爸爸级别的存在,极其的重要!!!以后我会详细详细再详细的讲清楚,特别爽!
我们接着上面的invokeBeanFactoryPostProcessors
源码继续看:
//此时ConfigurationClassPostProcessor完成了扫描,我们继续调用其他后置处理器
//查询程序员提供的BeanDefinitionRegistryPostProcessor后置处理器,
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//程序员提供的BeanDefinitionRegistryPostProcessor后置处理器必须实现Ordered接口,该接口用于排序
//spring按顺序调用
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;
}
}
打印结果:
最后,spring调用没有实现Ordered接口的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");
}
}
打印结果:
关于BeanDefinitionRegistryPostProcessor我们做个总结:
- 先调用spring内置的实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor后置处理器,只有ConfigurationClassPostProcessor。
- 再调用实现Ordered接口的BeanDefinitionRegistryPostProcessor后置处理器,包括内置和自定义的。
- 最后调用剩下的所有BeanDefinitionRegistryPostProcessor后置处理器。
调用完后继续看源码:
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
啥意思?还记得BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor方法吗?其实上面spring调用的是BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,而这行代码调用的是父接口BeanFactoryPostProcessor中的postProcessBeanFactory方法,完成同的功能。 很难!很绕!
调用完BeanDefinitionRegistryPostProcessor
紧接着调用BeanFactoryPostProcessor
后置处理器。
//查询实现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。
以上,我们初探了后置处理器的概念及调用过程。后续我们将深入分析后置处理器。