invokeBeanFactoryPostProcessors(上)
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//这里的参数getBeanFactoryPostProcessors()讲道理很容易误导大家,我在调试的时候发现它什么都没返回,注意他们的区别,list和map
//回到之前我所以提到的实现了BeanFactoryPostProcessor的Config类,按道理应该是有的,但是其实它拿到的是一个list,
//而我们是放在map里面的,所以这里它只是拿到程序员自己手动add的,注意注解方式也是拿不到的
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
看这里的参数getBeanFactoryPostProcessors()讲道理很容易误导人,我在调试的时候发现它什么都没返回,注意他们的区别,,这里会有个坑,如果读者尝试在我们的Main函数加上这段代码:
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext=
new AnnotationConfigApplicationContext(AppConfig.class);
annotationConfigApplicationContext.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
});
}
然后继续调试getBeanFactoryPostProcessors(),得出的结果会是多少呢,其实还是0,至于为什么,我们换一种写法
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.regisrer(Appconfig.class);
annotationConfigApplicationContext.addBeanFactoryPostProcessor();
annotationConfigApplicationContext.refresh();
再次调试getBeanFactoryPostProcessors(),得出结果为1,相信读者应该有多感悟。搞明白这个之后我们继续进入invokeBeanFactoryPostProcessors
这个方法,
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//注意这里的beanFactory是最基本的子类,这个类包含了如何对bean注册,创建,维护等功能,所以一定会进去
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//这里定义两个list是为了区分子类是实现了BeanFactoryPostProcessor,而且这里是装的程序员自己添加的
// 还是BeanDefinitionRegistryPostProcessor,因为这两个接口是父子关系,所以功能有所区别
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//这里肯定为空,前面已经说了,我们这里是程序员自己add的,而我们并没有
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
首先遍历beanFactoryPostProcessors,注意这个参数是我们传进来,是从getBeanFactoryPostProcessors()获取的,因此一般情况我们不会手动设置,所以这里都会为空,我们往下获取这个ConfigurationClassPostProcessor类后,Spring会合并之前两个循环的后置处理器,然后到主干方法invokeBeanDefinitionRegistryPostProcessors
我们在跟踪进去:
看第二句代码String[] candidateNames = registry.getBeanDefinitionNames();这里会拿出6个Name,添加到configCandidates里,看调试结果回想我在前文所提出的注册的后置处理器就明白为什么是6个,其目的就是为了找出我们的配置类,如果找到就标记成full,有些读者可能了解Spring的@configuration注解是配置类的意思,但不知道读者是否了解过加和不加这个注解的作用是什么,这里我们把@configuration注解注释掉,尝试运行会发现结果并不会报错,
至于为什么Spring搞这么个注解,笔者会在后文对@configuration的作用以及源码实现进行详细介绍,我们继续回到代码:
这里我们就拿到了我们的配置类,既然拿到了配置类,那么下一步就对配置类进行解析,看代码:
看到这句代码 parser.parse();这句代码是Spring解析的核心代码,我们点进去
这里判断需要解析的BeanDefinition是那种类型,这里回到我们的入口
,我们注册的是AppConfig配置类,但其实我们还可以配置普通类,比如我们直接将我们的User类放进去
随后我们在调试parse->processConfigurationClass->
-> doProcessConfigurationClass(configClass, sourceClass);
看第一段代码,如果我们的配置类有标识了@Component 这样的类
,可以看到已经找到这么一个类,这段代码我们点到为止,因为下面的配置类信息解析包含了这里的设计思想,所以这里不重点分析。
首先取出我们的扫描注解
然后执行 Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan,
sourceClass.getMetadata().getClassName());这段代码,这里就是解析的核心代码,我们跟进去,
我们进入doscan方法
这里我们看到在经过了findCandidateComponents(basePackage);这个方法后,Spring就已经拿到我了我们定义的注解类,我们继续进入
可以看出Spring真正解决包扫描结束是采用的ASM字节码提取技术,笔者对此也是一知半解,所以就不多做介绍了,有兴趣的读者们可以自行深入研究,这里我就不做文章了,我们还是回到代码,下面的代码不太重要,因此Spring拿到扫描出来的类后就返回,好的我们继续回到代码
在对普通注解类解析完后,会将普通类拿出来作为当做配置类继续递归解析,当然通常都会跳过,然后开始对@import注解解析,有些读者可能还没见过这个@import类,我们看下@Import注解类
,它的作用很清晰,目的就是向Spring容器注册类,看下实例:
这样就和在MyImportBeanDefinitionRegistrar加上@Component是一样效果,这里源码的细节我带着大家细看了,其目的就是解析@import三种类:普通类,ImportSelector,ImportBeanDefinitionRegistrar。这里我将笔记注释贴出来,大家自行理解:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
//这里是处理ImportSelector,转换成bd,放入一个集合
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
//这里是否是延迟执行,如果目标对象实现的是DeferredImportSelector,就表示需要延迟
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//这里是递归,因为Import的类可能还有Import,如果没有会递归到下面的普通类放入集合
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
//ImportBeanDefinitionRegistrar这个是Import的第二种类,实现可以直接拿到注册器
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
//将实现了ImportBeanDefinitionRegistrar的子类放进importBeanDefinitionRegistrars,后面spring会对其处理
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
//普通import类和ImportSelector都放进这个configurationClasses
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
读者这里重点对ImportBeanDefinitionRegistrar的作用进行分享,看下面实例:
如果我们继承了ImportBeanDefinitionRegistrar,那么我们就可以拿到BeanDefinitionRegistry,并就可以手动的向Spring添加一个 BeanDefinition,我们调试一下
当前我们的BeanDefinitionMap是11个,等到我们执行完这段代码后就会变成12个,看下图:
,我们改变了BeanDefinitionMap,而BeanDefinitionMap在Spring创建对象起到了绝对作用,所以我们就改变了Bean的创建,而这就是扩展Spring的一个接口之一,后期我们有机会的话我们会重点分享Spring-Mybatis和Spring-AOP是如何利用这些接口拓展的。
在对@Import注解解析完之后,又开始对配置类的@Bean解析
,然后我们继续回到代码,在执行完parse方法后
然后做校验,重点从这里开始->this.reader.loadBeanDefinitions(configClasses);,我们一直更进去会知道
这里就是对我们之前存储的@Import注解类进行运行,并且会执行自定义的@Import类,到目前为止我们总算跑完了
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);这句代码
接来下的内容笔者打算分开描述。