曹工说Spring Boot源码(30)– ConfigurationClassPostProcessor 实在太硬核了,为了了解它,我可能debug了快一天
- 2020 年 7 月 25 日
- 笔记
- spring/boot源码解析
写在前面的话
相关背景及资源:
曹工说Spring Boot源码(1)– Bean Definition到底是什么,附spring思维导图分享
曹工说Spring Boot源码(2)– Bean Definition到底是什么,咱们对着接口,逐个方法讲解
曹工说Spring Boot源码(3)– 手动注册Bean Definition不比游戏好玩吗,我们来试一下
曹工说Spring Boot源码(4)– 我是怎么自定义ApplicationContext,从json文件读取bean definition的?
曹工说Spring Boot源码(5)– 怎么从properties文件读取bean
曹工说Spring Boot源码(6)– Spring怎么从xml文件里解析bean的
曹工说Spring Boot源码(7)– Spring解析xml文件,到底从中得到了什么(上)
曹工说Spring Boot源码(8)– Spring解析xml文件,到底从中得到了什么(util命名空间)
曹工说Spring Boot源码(9)– Spring解析xml文件,到底从中得到了什么(context命名空间上)
曹工说Spring Boot源码(10)– Spring解析xml文件,到底从中得到了什么(context:annotation-config 解析)
曹工说Spring Boot源码(11)– context:component-scan,你真的会用吗(这次来说说它的奇技淫巧)
曹工说Spring Boot源码(12)– Spring解析xml文件,到底从中得到了什么(context:component-scan完整解析)
曹工说Spring Boot源码(13)– AspectJ的运行时织入(Load-Time-Weaving),基本内容是讲清楚了(附源码)
曹工说Spring Boot源码(14)– AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成
曹工说Spring Boot源码(15)– Spring从xml文件里到底得到了什么(context:load-time-weaver 完整解析)
曹工说Spring Boot源码(16)– Spring从xml文件里到底得到了什么(aop:config完整解析【上】)
曹工说Spring Boot源码(17)– Spring从xml文件里到底得到了什么(aop:config完整解析【中】)
曹工说Spring Boot源码(18)– Spring AOP源码分析三部曲,终于快讲完了 (aop:config完整解析【下】)
曹工说Spring Boot源码(19)– Spring 带给我们的工具利器,创建代理不用愁(ProxyFactory)
曹工说Spring Boot源码(20)– 码网恢恢,疏而不漏,如何记录Spring RedisTemplate每次操作日志
曹工说Spring Boot源码(21)– 为了让大家理解Spring Aop利器ProxyFactory,我已经拼了
曹工说Spring Boot源码(22)– 你说我Spring Aop依赖AspectJ,我依赖它什么了
曹工说Spring Boot源码(23)– ASM又立功了,Spring原来是这么递归获取注解的元注解的
曹工说Spring Boot源码(24)– Spring注解扫描的瑞士军刀,asm技术实战(上)
曹工说Spring Boot源码(25)– Spring注解扫描的瑞士军刀,ASM + Java Instrumentation,顺便提提Jar包破解
曹工说Spring Boot源码(26)– 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎
曹工说Spring Boot源码(27)– Spring的component-scan,光是include-filter属性的各种配置方式,就够玩半天了
曹工说Spring Boot源码(28)– Spring的component-scan机制,让你自己来进行简单实现,怎么办
曹工说Spring Boot源码(29)– Spring 解决循环依赖为什么使用三级缓存,而不是二级缓存
工程结构图:
本篇前言
本篇是单独基于spring-boot 2.1.7.RELEASE的版本写的,本来没有这篇文章的,本来正在写遇到的一个eureka client的问题,然后有一个eureka的自动配置类,我当时准备讲解一下:
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@Import(DiscoveryClientOptionalArgsConfiguration.class)
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = {
"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration"})
public class EurekaClientAutoConfiguration {
结果,我发现,对于这一坨注解的执行顺序,我并不是很了解,本来以为是spring.factories里配置了这个类,因此最早的入口是在那里,结果,实际debug起来,发现好像并不是,而是由另外一个eureka的自动配置类触发的。
因此,纠结半天,干脆好好好好学研究下spring boot/cloud下configuration类的处理过程。
测试代码
就是一个普通的spring boot下的eureka client程序,pom大致如下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web </artifactId>
</dependency>
</dependencies>
一个误会
一点点常识,大家可能都知道ConfigurationClassPostProcessor,这个类,负责处理各种@configuration注解配置的类(full模式),也包括轻量模式下的配置类(没有@configuration配置,但是有@bean方法等)。
ConfigurationClassPostProcessor实现了如下接口:
实现了BeanDefinitionRegistryPostProcessor,总体来说,是对beanDefinition进行各种后置处理,比如增删改beanDefinition。
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;
}
这个方法,就是对beanFactory进行后置处理,而后置处理主要干啥呢,就是增加beanDefinition,比如我们一个类A上,注解@configuration,同时注解@Import,导入了其他类。
那么,就在这个方法中,就会去扫描configuration配置的类,比如扫描到类A,然后去获取类A上的注解,然后递归获取类A上的注解的元注解,最终检查其中:是否有PropertySource、是否有ComponentScan、是否有Import、是否有@bean方法等等,去获取更多的beanDefinition回来,并注册到beanFactory。
因此,入口基本就是在 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
。
因此,我把断点打在 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
,准备把这个各种注解的处理顺序搞清楚。
结果,我跟了大半天,还了解了:
在spring cloud下,是有两个applicationContext(如果有feign调用,会有更多,这里暂不考虑)。
其中一个,就是bootStrap applicationContext;另外一个,才是应用程序本身的applicationContext。
而且,bootStrap applicationContext 是应用本身的applicationContext的parent。
我一开始没注意到有两个,因为我以为只有配置了bootStrap.yml才会有;结果跟了很久,都没到我的应用的类,才意识到这个问题。
所以呢,跟了半天多的东西,其实是bootStrap applicationContext的东西,不过代码逻辑都是一样的;而且,学习bootStrap applicationContext也很有必要。
let‘s start
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
/**
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
...
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
这里没多少东西,主要就是最后一行开始:
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
该方法比较长,其实是ConfigurationClassPostProcessor太核心了,几乎是spring boot的基石,所以只能分为多个部分来顺序讲解。
获取候选bean集合
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
断点显示,这里获取到了,如下candidate:
过滤出configuration注解的类
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
上面的几个候选类,经过这里筛选后,只剩下一个满足条件的bean。
bootstrapImportSelectorConfiguration
生成configuration类解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
这个类,没有继承任何类,也没有实现任何接口
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
// 1
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
// 2
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
这里1处,new了一个bean扫描解析器。
public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {
this.environment = environment;
this.resourceLoader = resourceLoader;
this.beanNameGenerator = beanNameGenerator;
this.registry = registry;
}
2处,创建了一个condition计算器,负责各种@condition的解析计算。
public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
this.context = new ConditionContextImpl(registry, environment, resourceLoader);
}
使用ConfigurationClassParser循环解析
do {
// 1
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
接下来,先进入1处。
ConfigurationClassParser#parse
注意,进入此处时,参数configCandidates的值为:
该holder中,就包含beanName和beanDefinition,其中bean对应的class类型为:
org.springframework.cloud.bootstrap.BootstrapImportSelectorConfiguration
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 1
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
}
this.deferredImportSelectorHandler.process();
}
这里会进入1处。
在进入该方法前,获取了beanDefinition中的MetaData。
(AnnotatedBeanDefinition) bd).getMetadata()
protected final void parse(AnnotationMetadata metadata, String beanName) {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
这里先去new了一个ConfigurationClass。
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
this.metadata = metadata;
this.resource = new DescriptiveResource(metadata.getClassName());
this.beanName = beanName;
}
这个类,主要是对于@configuration注解标注的类的封装。
/**
* Represents a user-defined {@link Configuration @Configuration} class.
* Includes a set of {@link Bean} methods, including all such methods
* defined in the ancestry of the class, in a 'flattened-out' manner.
*
*/
final class ConfigurationClass {
开始解析
org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
protected void processConfigurationClass(ConfigurationClass configClass) {
// 1
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
1处,使用condition计算器,进行判断,看看该bean是否满足
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
因为org.springframework.cloud.bootstrap.BootstrapImportSelectorConfiguration
类上,并没有condition注解,所以是默认生效的。
接下来进入下面的地方:
protected void processConfigurationClass(ConfigurationClass configClass){
// 0
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 1
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
else {
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 2
SourceClass sourceClass = asSourceClass(configClass);
do {
// 3
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
-
0,就是前面说的判断condition是否满足
-
1,此时不满足条件,直接跳过
-
2,这里根据注解信息,获取sourceClass,不用细究
private SourceClass asSourceClass(ConfigurationClass configurationClass){ AnnotationMetadata metadata = configurationClass.getMetadata(); if (metadata instanceof StandardAnnotationMetadata) { return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass()); } return asSourceClass(metadata.getClassName()); }
-
3处,继续解析。
这个类较长,我们下面细讲。
doProcessConfigurationClass
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass){
// 3.1
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
//3.2 Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
这里实际上,会进入3.1处。因为这个类上,加了@configuration注解的。
@Configuration
@Import(BootstrapImportSelector.class)
public class BootstrapImportSelectorConfiguration {
}
处理member类
然后3.2处,member类处理,这里暂时不太清楚member类是什么,不过我们这个BootstrapImportSelectorConfiguration
也没有获取到任何的member class,所以先跳过。
处理PropertySource
接下来,开始解析bean的class上,是否注解了PropertySource.
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
}
这里,我们并没有注解PropertySource,所以也会跳过。
处理componnet-scan
这里也没有,跳过。
处理@imort
processImports(configClass, sourceClass, getImports(sourceClass), true);
在processImports之前,这里第三个参数,先去调用了getImports。
getImports
/**
* Returns {@code @Import} class, considering all meta-annotations.
*/
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
Set<SourceClass> visited = new LinkedHashSet<>();
collectImports(sourceClass, imports, visited);
return imports;
}
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.equals(Import.class.getName())) {
// 1
collectImports(annotation, imports, visited);
}
}
// 2
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
-
1,递归调用自己,获取@Import注解
-
2,将@import注解中value的值取出来,放到imports中。
这里处理完成后,我们获取到的东西如下:
即:
org.springframework.cloud.bootstrap.BootstrapImportSelector
processImport
processImports(configClass, sourceClass, getImports(sourceClass), true);
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
this.importStack.push(configClass);
try {
// 0
for (SourceClass candidate : importCandidates) {
// 1
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);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 2
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);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 3
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
}
- 1处,当要import的是ImportSelector接口时
- 2处,当要import的bean class是:ImportBeanDefinitionRegistrar
- 3处,当要import的是普通的configuration class时。
我们这里这个类,是实现了DeferredImportSelector
,间接实现了ImportSelector
:
public class BootstrapImportSelector implements EnvironmentAware, DeferredImportSelector
所以要进入下面这一坨逻辑:
for (SourceClass candidate : importCandidates) {
// 1
if (candidate.isAssignable(ImportSelector.class)) {
//2 Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
// 3
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
// 4
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
// 5
if (selector instanceof DeferredImportSelector) {
// 6
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
- 1, 判断如果是实现了ImportSelector
- 2,加载对应的bean class
- 3,通过反射实例化该bean
- 4,调用aware方法,注入environment等
- 5,判断是否为DeferredImportSelector,该类型需要被延迟import
- 6,处理该DeferredImportSelector
6处,使用专门的handler,来处理DeferredImportSelector类型的bean。
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
// 1
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
configClass, importSelector);
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
// 2
this.deferredImportSelectors.add(holder);
}
}
-
1,将configClass,和importSelector放进一个holder中。
public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) { this.configurationClass = configClass; this.importSelector = selector; }
-
2,往如下的list中,添加一个holder实例。
@Nullable private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
到这里,基本@import就处理完了,因为前面这个importSelector是deferred类型,是需要延期处理的,所以,加入该list后,处理结束。
处理@bean方法
这里没有bean方法,跳过。
处理接口中的默认方法
这个暂时不涉及,跳过。
处理deferredImportSelector
org.springframework.context.annotation.ConfigurationClassParser#parse
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 0
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 1
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
}
// 2
this.deferredImportSelectorHandler.process();
}
接下来,我们回到之前的代码,1处的parse方法终于处理结束了,本来应该进入0处的下一轮循环,但是这里因为集合中只有那么一个元素:bootstrapImportSelectorConfiguration。所以这步就算处理完了。
进入到2处。
org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler#process
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
//1
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 2
deferredImports.forEach(handler::register);
// 3
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
- 1,new了一个handler,专门处理这种延迟导入的bean selector
- 2,对需要延迟导入的bean selector,进行遍历,然后调用handler的register
- 3,调用handler的批量import方法。
我们对2处和3处重点讲解。
handler::registered
public void register(DeferredImportSelectorHolder deferredImport) {
// 0
Class<? extends Group> group = deferredImport.getImportSelector()
.getImportGroup();
// 1
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 2
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
-
0,从holder二元组中,获取importSelector,然后获取其importGroup。
这里的group为null。
public interface DeferredImportSelector extends ImportSelector { /** * Return a specific import group. * <p>The default implementations return {@code null} for no grouping required. * @return the import group class, or {@code null} if none * @since 5.0 */ @Nullable default Class<? extends Group> getImportGroup() { return null; }
-
1处,比较复杂。
这里有个field:
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
1处我们可以看出,是在往上面这个map,放东西。
key:
(group != null ? group : deferredImport)
因为我们这里group为null,所以这里的key为:
DeferredImportSelectorHolder deferredImport
,也就是那个二元组。value是啥呢?
key -> new DeferredImportSelectorGrouping(createGroup(group))
我们先看看createGroup吧:
private Group createGroup(@Nullable Class<? extends Group> type) { // 1 Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class); Group group = BeanUtils.instantiateClass(effectiveType); ParserStrategyUtils.invokeAwareMethods(group, ConfigurationClassParser.this.environment, ConfigurationClassParser.this.resourceLoader, ConfigurationClassParser.this.registry); return group; }
1处,因为我们传入的参数:type为null,所以这里场景了一个DefaultDeferredImportSelectorGroup的实例,填充Aware字段后,返回。
然后,我们利用createGroup返回的实例,传给了:
key -> new DeferredImportSelectorGrouping(createGroup(group))
然后看看这个类呢:
private static class DeferredImportSelectorGrouping { private final DeferredImportSelector.Group group; private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>(); // 1 DeferredImportSelectorGrouping(Group group) { this.group = group; }
-
2,我们上面一步,往map里放了个key、value。
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
-
3,现在需要往value(类型为DeferredImportSelectorGrouping),加入一个延迟importSelector的holder
public void register(DeferredImportSelectorHolder deferredImport) { Class<? extends Group> group = deferredImport.getImportSelector() .getImportGroup(); DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent( (group != null ? group : deferredImport), key -> new DeferredImportSelectorGrouping(createGroup(group))); // grouping.add(deferredImport); this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass()); }
org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#add public void add(DeferredImportSelectorHolder deferredImport) { this.deferredImports.add(deferredImport); }
-
注册
public void register(DeferredImportSelectorHolder deferredImport) { Class<? extends Group> group = deferredImport.getImportSelector() .getImportGroup(); DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent( (group != null ? group : deferredImport), key -> new DeferredImportSelectorGrouping(createGroup(group))); grouping.add(deferredImport); // 4 this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass()); }
然后进入到上面的4处,这里把这个延迟importSelector的metadata作为key,configurationClass作为value,放进map。
private class DeferredImportSelectorGroupingHandler { private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>(); // 1 private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
即上面1处这个map。
进行group import
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 0
deferredImports.forEach(handler::register);
// 1
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
前面已经把0处,讲解完毕;这里进入1处。
org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports
private Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
public void processGroupImports() {
// 1
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 2
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(
entry.getMetadata());
try {
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
}
});
}
}
-
1处,我们这里遍历groupings这个map的value集合
-
2,获取这个grouping中的要import的集合
org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>(); /** * Return the imports defined by the group. * @return each import with its associated configuration class */ public Iterable<Group.Entry> getImports() { // 1 for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { // 2 this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } return this.group.selectImports(); }
- 1,遍历全部的holder
- 2,获取holder中的,这个importSelector的类的元数据,和importSelector本身,传给this.group.process方法。
我们看看这里的process方法
org.springframework.context.annotation.ConfigurationClassParser.DefaultDeferredImportSelectorGroup private static class DefaultDeferredImportSelectorGroup implements Group { private final List<Entry> imports = new ArrayList<>(); @Override public void process(AnnotationMetadata metadata, DeferredImportSelector selector) { // 1 for (String importClassName : selector.selectImports(metadata)) { this.imports.add(new Entry(metadata, importClassName)); } } @Override public Iterable<Entry> selectImports() { return this.imports; } }
这里的1处,即调用了selector接口的方法了
public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on * the {@link AnnotationMetadata} of the importing @{@link Configuration} class. */ String[] selectImports(AnnotationMetadata importingClassMetadata); }
1处的selector.selectImports,我们可以看到,传进去了一个metadata,这个metaData都有啥数据呢?
我们再看一眼下面这个类:
@Configuration @Import(BootstrapImportSelector.class) public class BootstrapImportSelectorConfiguration { }
所以,传入的metaData就是这个被@Import注解,注解了的类的信息。
相当于说,你在类A上加上@Import注解,那么最终类A的信息,会被当做参数,传给ImportSelector的selectImports方法。
BootstrapImportSelector
前面说到了这个selector实现了DeferredImportSelector,我们看看怎么实现的吧:
public class BootstrapImportSelector implements EnvironmentAware, DeferredImportSelector {
private Environment environment;
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 1
List<String> names = new ArrayList<>(SpringFactoriesLoader
.loadFactoryNames(BootstrapConfiguration.class, classLoader));
// 2
names.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(
this.environment.getProperty("spring.cloud.bootstrap.sources", ""))));
// 3
List<OrderedAnnotatedElement> elements = new ArrayList<>();
for (String name : names) {
try {
elements.add(
// 4
new OrderedAnnotatedElement(this.metadataReaderFactory, name));
}
catch (IOException e) {
continue;
}
}
AnnotationAwareOrderComparator.sort(elements);
String[] classNames = elements.stream().map(e -> e.name).toArray(String[]::new);
// 5
return classNames;
}
-
1,从spring.factories中,查找以
org.springframework.cloud.bootstrap.BootstrapConfiguration
为key的property。我们目前这个代码中,在如下文件,找到了一处:
然后在eureka的jar包,找到一个:
所以,我们拿到了5个值。
-
2处,从spring.cloud.bootstrap.sources属性中获取
-
3处,遍历所有这些要import的类名
-
4处,将类名转换为OrderedAnnotatedElement,这个会获取对应的类的元数据,然后获取其上注解的@order来获取顺序
OrderedAnnotatedElement(MetadataReaderFactory metadataReaderFactory, String name) throws IOException { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(name); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); Map<String, Object> attributes = metadata .getAnnotationAttributes(Order.class.getName()); this.name = name; if (attributes != null && attributes.containsKey("value")) { this.value = (Integer) attributes.get("value"); this.order = new Order() { @Override public Class<? extends Annotation> annotationType() { return Order.class; } @Override public int value() { return OrderedAnnotatedElement.this.value; } }; } }
-
5处返回排序后的,要import的class的类名。
将要import的类名,存放起来
private static class DefaultDeferredImportSelectorGroup implements Group {
private final List<Entry> imports = new ArrayList<>();
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
// 1
for (String importClassName : selector.selectImports(metadata)) {
// 2
this.imports.add(new Entry(metadata, importClassName));
}
}
@Override
public Iterable<Entry> selectImports() {
return this.imports;
}
}
前面讲完了1处,现在看看2处。
2处就是将前面拿到的5个要import的类,加入到这里的imports 集合中。
此时,imports集合如下:
递归处理下一个configuration class
上面我们获取到了5个要import的class。
org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 1
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(
entry.getMetadata());
try {
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
}
});
}
}
这里1处的grouping.getImports,就能拿到那5个元素。
这里又去开始循环处理,看下图。
处理PropertySourceBootstrapConfiguration
我们看看这个类
@Configuration
@EnableConfigurationProperties(PropertySourceBootstrapProperties.class)
public class PropertySourceBootstrapConfiguration implements
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// 1
...
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// 2
...
}
else {
// 3 process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 4
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
}
因为其没有实现ImportSelector等,所以进入3处,当做普通的Configuration类处理。
private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {
private final MultiValueMap<String, AnnotationMetadata> imports = new LinkedMultiValueMap<>();
//
public void registerImport(AnnotationMetadata importingClass, String importedClass) {
// 1
this.imports.add(importedClass, importingClass);
}
这里直接把其放到map中。
然后进入了前面的4处:
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 4
processConfigurationClass(candidate.asConfigClass(configClass));
}
org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 1
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
...
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
// 2
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
和之前一样,这里,1处,判断是否满足condition注解,因为我们的PropertySourceBootstrapConfiguration,并没有condition,所以是默认生效的。
处理member类
不涉及。
处理PropertySource注解
不涉及。
处理ComponentScan注解
不涉及
处理import注解
由于该类上,加了
@Configuration
@EnableConfigurationProperties(PropertySourceBootstrapProperties.class)
public class PropertySourceBootstrapConfiguration
而:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesImportSelector.class)
public @interface EnableConfigurationProperties {
所以,处理这里时:
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
在getImports调用,得到如下返回。
org.springframework.boot.context.properties.EnableConfigurationPropertiesImportSelector
然后开始处理该import。
由于其实现了ImportSelector,会进入下面的地方。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
//1 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);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 2
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
-
1,反射创建该selector
-
2,调用该selector的selectImport方法,得到要import的类
class EnableConfigurationPropertiesImportSelector implements ImportSelector { private static final String[] IMPORTS = { ConfigurationPropertiesBeanRegistrar.class.getName(), ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName() }; @Override public String[] selectImports(AnnotationMetadata metadata) { return IMPORTS; }
这里,我们就拿到了2个要import的类的类名。
接下来,又开始对这两个要import的类,进行处理。
for (SourceClass candidate : importCandidates) {
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);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 1
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
即上面的1这一处地方,进行递归处理,此时要import的两个类,是这样的:
咱们这里不展开了,没完了。。
处理ImportResource注解
不涉及
处理bean方法
不涉及
处理EncryptionBootstrapConfiguration
@Configuration
@ConditionalOnClass({ TextEncryptor.class })
@EnableConfigurationProperties({ KeyProperties.class })
public class EncryptionBootstrapConfiguration {
这个类,大家看看就好。没有新东西,不会说再去import什么东西。
不过这个类上就有condition条件了。
在如下方法时,使用condition计算器,就会发现真的有一个condition要计算。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
然后就又是同样流程,处理member、处理PropertySource、ComponentScan等等。
跳过后续的3个configuration类的处理
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\
org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
这些都跳过,道理类似的。
parse完成后的后续处理
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
...
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 1
parser.parse(candidates);
// 2
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
...
}
整个过程比较复杂,我们这里分析了那么多,主要是把1处的代码说的差不多了。
2处,加载beanDefinition。
经过这个步骤后,beanFactory中的bean如下:
总结
到此的话,几乎差不多吧,细节还是很多,有些地方肯定没讲到,后续再补上。
demo的源码本身很简单,如果大家需要,可以从这里获取:
//gitee.com/ckl111/all-simple-demo-in-work-1/tree/master/eureka/