这些不知道,别说你熟悉 Spring( 二 )


在该背景下出现了 SpringBoot,SpringBoot 可以说是稳住了 Java 的地位 。SpringBoot 提供了自动装配功能 , 自动装配简单来说就是将某种功能(如 web 相关、redis 相关、logging 相关等)打包在一起,统一管理依赖包版本,并且约定好相关功能 Bean 的装配规则,使用者只需引入一个依赖,通过少量注解或简单配置就可以使用第三方组件提供的功能了 。
在 SpringBoot 中这类功能组件有一个好听的名字叫做 starter 。比如 spring-boot-starter-web、spring-boot-starter-data-redis、spring-boot-starter-logging 等 。starter 里会通过 @Configuration + @Bean + @ConditionalOnXXX 等注解定义要注入 Spring 中的 Bean , 然后在 spring.factories 文件中配置为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的实现,就可以完成自动装配了 。
具体装配流程怎么样的呢?
其实也很简单,基本都是 Spring 中的知识,没啥新颖的 。主要依托于@EnableAutoConfiguration 注解,该注解上会 Import 一个 AutoConfigurationImportSelector , 看下继承关系,该类继承于 DeferredImportSelector 。

这些不知道,别说你熟悉 Spring

文章插图
主要方法为 getAutoConfigurationEntry()
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {// 1if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);// 2List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations);// 3Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 4configurations = getConfigurationClassFilter().filter(configurations);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions); }方法解读
  1. 通过 spring.boot.enableautoconfiguration 配置项判断是否启用自动装配 , 默认为 true
  2. 使用上述说的 SpringFactoriesLoader.loadFactoryNames() 加载所有 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的实现类的全限定类名,借助 HashSet 进行去重
  3. 获取 @EnableAutoConfiguration 注解上配置的要 exclude 的类,然后排除这些特定类
  4. 通过 @ConditionalOnXXX 进行过滤,满足条件的类才会留下 , 封装到 AutoConfigurationEntry 里返回
那 getAutoConfigurationEntry() 方法在哪儿调用呢?
public void refresh() throws BeansException, IllegalStateException {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// 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(); }以上是 Spring 容器刷新时的几个关键步骤,在步骤二 invokeBeanFactoryPostProcessors() 中会调用所有已经注册的 BeanFactoryPostProcessor 进行处理 。此处调用也是有顺序的 , 优先会调用所有 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(),BeanDefinitionRegistryPostProcessor 是一个特殊的 BeanFactoryPostProcessor,然后再调用所有 BeanFactoryPostProcessor#postProcessBeanFactory() 。
ConfigurationClassPostProcessor 是 BeanDefinitionRegistryPostProcessor 的一个实现类,该类主要用来处理 @Configuration 注解标注的类 。我们用 @Configuration 标注的类会被 ConfigurationClassParser 解析包装成 ConfigurationClass 对象,然后再调用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass() 进行 BeanDefination 的注册 。
其中 ConfigurationClassParser 解析时会递归处理源配置类上的注解(@PropertySource、@ComponentScan、@Import、@ImportResource)、 @Bean 标注的方法、接口上的 default 方法,进行 ConfigurationClass 类的补全填充,同时如果该配置类有父类,同样会递归进行处理 。具体代码请看 ConfigurationClassParser#doProcessConfigurationClass() 方法

推荐阅读