一、前言

  • Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。
  • 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

二、BeanFactoryPostProcessor

BeanFactoryPostProcessor是在bean初始化之前对bean的统一操作

package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;@FunctionalInterface
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}

它还有个子接口:BeanDefinitionRegistryPostProcessor

package org.springframework.beans.factory.support;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}

BeanDefinitionRegistryPostProcessor在BeanFactoryPostProcessor之前执行

三、源码分析

从main方法入口进入到SpringApplication的run方法

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);prepareContext(context, environment, listeners, applicationArguments,printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;
}

进入到refreshContext里面:

@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}
}

主要用到的就是postProcessBeanFactory方法和invokeBeanFactoryPostProcessors方法

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}
}

postProcessBeanFactory主要是扫描包

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {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()));}
}

调用在invokeBeanFactoryPostProcessors方法里面

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {// 先折叠上...}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();
}
  • 折叠部分先不看,往下看
  • 根据 beanFactory.getBeanNamesForType 取出BeanFactoryPostProcessor
  • 根据priorityOrder , order , nonOrder分成三个list
  • 对priorityOrderlist排序,执行invokeBeanFactoryPostProcessors
  • 对orderlist排序,执行invokeBeanFactoryPostProcessors
  • 对nonOrderlist排序,执行invokeBeanFactoryPostProcessors
private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {for (BeanFactoryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanFactory(beanFactory);}
}
  • 执行invokeBeanFactoryPostProcessors很简单,如上
  • 我们在看一下折叠的部分
Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.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));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {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();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
  • 如果类型是:BeanDefinitionRegistryPostProcessor,就执行registryProcessor.postProcessBeanDefinitionRegistry(registry);
  • 同样按Priority,order,nonOrder的顺序执行registryProcessor.postProcessBeanDefinitionRegistry
  • 分成两个list: regularPostProcessors(父接口)和registryProcessors(子接口)
  • 先执行registryProcessors的invoke,再执行regularPostProcessors的invoke

总结一下:

  • 如果类型是BeanDefinitionRegistryPostProcessor,就执行registryProcessor.postProcessBeanDefinitionRegistry(registry);
  • 按Priority,order,nonOrder的顺序执行BeanDefinitionRegistryPostProcessor
  • 上一步执行完了,执行registryProcessors的invoke, 再执行regularPostProcessors的invoke
  • 最后按Priority,order,nonOrder的顺序执行普通的BeanFactoryPostProcessor

欢迎关注微信公众号:丰极,更多技术学习分享。

springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)相关推荐

  1. SpringBoot源码解析

    SpringBoot源码解析 1.启动的过程: 首先在main函数中启动当前应用程序(SpringApplication启动) 创建SpringApplication对象(new SpringAppl ...

  2. 《React源码解析》系列完结!

    前言 距离第一篇<React源码解析(一)>已经过去将近4个月的时间,由于是我第一次进行源码解析相关的写作,思路和文笔还不够成熟.一百多天以来,我基于读者反馈反思这几篇文章中的不足,同时也 ...

  3. springboot源码解析autoconfigure之WebMvcAutoConfiguration

    2019独角兽企业重金招聘Python工程师标准>>> 说在前面 本次开始spring-boot-autoconfigure源码解析之WebMvcAutoConfiguration ...

  4. maven 公共模块依赖_「spring-boot 源码解析」spring-boot 依赖管理

    问题 maven 工程,依赖管理是非常基本又非常重要的功能,现在的工程越来越庞大,依赖越来越多,各种二方包.三方包太多太多,依赖冲突处理起来真是让人头疼,经常需要涉及到多个地方需要调整. 微信公众号: ...

  5. 【java】spring-boot源码解析之应用启动

    spring boot 项目使用默认配置的思想,极大的简化了 spring 项目的开发.下面的代码就是一个最简单的 spring 项目: @SpringBootApplication public c ...

  6. SpringBoot源码解析(十一)@Primary

    在SpringBoot中有许多类使用到了@Primary注解,关于用法,请看这篇博客:在spring中常被忽视的注解 @Primary. 这次我们不说用法,从源码层面来看下: 一.入口 在创建bean ...

  7. SpringBoot 源码解析——如何进行源码环境调试?

    已经分析过 spring-boot-tests/spring-boot-smoke-tests 下的冒烟测试和很早之前版本的 sample 是一样的,所以我们想直接利用这些 sample code 来 ...

  8. spring-boot源码解析之AnnotationConfigServletWebServerApplicationContext

    文章目录 主要功能 Factory Constructor Additional Component Candidates Parent Class ServletWebServerApplicati ...

  9. SpringBoot源码解析(七)EnvironmentPostProcessor

    本文将重点介绍SpringBoot提供给我们的另一个扩展点EnvironmentPostProcessor,它允许我们到任意的指定目录.以任意的方式加载一组配置,并赋予任意的优先级 上文对prepar ...

最新文章

  1. 自学python推荐书籍2019-入门必看 | 大佬们推荐的Python书单汇总
  2. C/C++笔试、面试题
  3. 用 JA Transmenu 模块做多级弹出菜单
  4. shell获取当前执行脚本的路径
  5. 电脑系统如何锁定计算机,如何删除“解除计算机锁定”页面?
  6. 自定义添加的鼠标事件
  7. 【angularjs】【学习心得】路由继续研究篇
  8. UVa10491 Cows and Cars
  9. MCS:连续随机变量——Erlang分布
  10. PHP帮管客CRM系统源码去域名授权v2.4.4版
  11. 河南自考本科英语可用计算机代替,河南自考选考2至3门专业课可代替英语课程...
  12. Google Chrome 提示 Adobe Flash Player 不是最新版本
  13. Python dict字典keys()、values()和items()方法
  14. js下载文件格式为Excel后提示与文件扩展名不一致,打开文件前请验证文件没有损坏且来源可信.
  15. docker编译speccpu2017
  16. 【通信】Matlab实现多同步压缩变换
  17. html实现五子棋ai,JS实现五子棋——AI篇
  18. 一名优秀的数据分析师,应该具备哪些基本素质?
  19. 因为计算机中丢失d3dx926.dll,win10系统打开程序提示丢失d3dx9 26.dll的解决方法
  20. 网间进程的标识和端口分配机制

热门文章

  1. 设置主机名和hosts映射
  2. NRF52840 Reset 复位后板子起不来及解决方法
  3. Idea Diagrams生成UML类图
  4. memoQ电子书 | 聚焦视频翻译技术
  5. 淘宝店铺运营新方向, 分销模式助力店铺腾飞!
  6. 雷达系统设计matlab仿真 代码,《雷达系统设计matlab仿真》
  7. 《C++捷径教程》学习笔记【一】:虚函数
  8. 网页图片下载不了?不,仅需三步即可
  9. c/c++ 结束进程的方法
  10. 数字信号处理|用Matlab画复指数序列的实部、虚部、幅值、相位图