一、解析配置类核心流程
获取到所有的配置类之后,对它们进行排序,按照优先级对它们进行解析
// Sort by previously determined @Order value, if applicable
// 通过@Order可以排序,升序排序,order越小越靠前
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
下面生成配置类解析对象,进行解析
// 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 {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass
// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass
// 解析配置类的结果是什么?
parser.parse(candidates); // AppConfig.class--->BeanDefinition
……
}
while (!candidates.isEmpty());
1.1 循环解析
遍历所有配置类,依次进行解析
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
// 解析BeanDefinition所对应的类
if (bd instanceof AnnotatedBeanDefinition) {
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());
}
}
// 处理deferredImportSelectors,表示当前所有配置类解析完了之后才执行
// deferredImportSelector表示推迟的ImportSelector,正常的ImportSelector是在解析配置类的过程中执行的
this.deferredImportSelectorHandler.process();
}
对元数据进行包装
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
// 把类的元信息和beanName封装为ConfigurationClass
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
如果类上有@Conditional注解,只有条件满足时才会进行解析
当前配置类可能是某个类的子类,所以解析完当前类后,再去解析其父类,知道没有父类为止
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 条件注解,就是看有没有类上是否有@Conditional注解,如果有,则进行条件匹配
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
……
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
// ConfigurationClass重写了equals方法,只要两个ConfigurationClass对应的className相等就可以
this.configurationClasses.put(configClass, configClass);
}
1.2 处理@Component注解内部类
如果类上有@Component注解,则去判断是否有内部类为配置类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
// 处理内部类
// 在解析一个配置类时,如果类上有@Component,则会判断内部类是不是lite配置类并进行解析,并且会记录为被导入的
processMemberClasses(configClass, sourceClass, filter);
}
如果有内部类,与前面判断配置类一样的逻辑,进行判断,然后排序,接着遍历进行递归解析,如果出现了循环引入的情况,直接抛异常
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate<String> filter) throws IOException {
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 内部类是不是lite配置类
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
// 排序
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
// AppConfig中有一个内部类A, A上用@Import导入AppConfig.class,就出现了循环import
if (this.importStack.contains(configClass)) {
// 就是直接抛异常
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
1.3 处理@PropertySources注解配置类
解析@PropertySources指定的配置文件,然后将属性添加到environment
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
1.4 处理@ComponentScan注解配置类
判断当前配置类上面有@ComponentScan或@ComponentScans注解
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
如果有这两种注解,则获取注解上的参数,然后根据value指定的包路径,调用componentScanParser的parse()去进行扫描,里面具体的调用就是《BeanDefinition创建过程》中介绍的doScan()方法
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
// 这里就会进行扫描,得到的BeanDefinition会注册到Spring容器中
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
……
}
}
}
扫描会生成新的BeanDefiniton,然后再去判断这些新生成的BeanDefinition中是否有配置类,如果有递归调用解析方法进行解析
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 检查扫描出来的BeanDefinition是不是配置类(full和lite)
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
1.5 处理@Import注解配置类
根据getImports(sourceClass)去获取当前配置类上Import注解引入的类,以及配置类上其他注解通过Import导入的类,然后调用processImports()去解析@Import注解
// Process any @Import annotations
// getImports(sourceClass)会拿到@Import导入的类
// 如果导入的是普通类,那么会直接把它当做配置类来解析
// 如果导入的是普通ImportSelector,那么会将返回的类再次调用processImports()
// 如果导入的是特殊ImportSelector,DeferredImportSelector,那么暂时不会处理,会在解析完所有当前这轮配置类后进行导入,将返回的类再次调用processImports()
// 如果导入的是ImportBeanDefinitionRegistrar,那么暂时不会处理,会在解析完所有当前这轮配置类后,将配置类解析成为BeanDefinition之后进行调用
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
如果没有@Import注解指定的类,直接返回
如果出现了循环引入,则直接报错
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
……
}
遍历Import导入进来的类,如果import的类实现了ImportSelector接口,则将该类进行实例化,然后进一步判断该类是否是DeferredImportSelector类型,如果是该类型,则加入到deferredImportSelectorHandler,表示推迟执行,会在当前这一轮配置类扫描后执行,而不是所有配置都扫描完执行
如果是一个普通的ImportSelector,则调用它的selectImports()方法得到导入的类,递归调用processImports()方法进行解析
for (SourceClass candidate : importCandidates) {
// 如果import的类实现了ImportSelector接口
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
//加载类,创建实例
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
// 如果import的是DeferredImportSelector,表示推迟导入
//
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
} else {
// 如果import的是普通的ImportSelector
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
// 继续处理selectImports()所返回的类
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
……
}
如果导入的类实现了ImportBeanDefinitionRegistrar接口,则将其实例化之后,通过addImportBeanDefinitionRegistrar缓存在当前配置类的importBeanDefinitionRegistrars属性中
如果Import的就是一个普通的类,不满足上述的两大类条件,则会把这个普通的类直接当作配置类去进行配置类解析
// 如果import的类实现了ImportBeanDefinitionRegistrar接口
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 =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
// 如果import的类就是普通的类
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedBy
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
在配置类的最上层解析方法中,当遍历解析完这一轮所有的配置类之后,才会去处理@Import注解导入的DeferredImportSelector类型的类
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
//解析配置类
……
}
// 处理deferredImportSelectors,表示当前所有配置类解析完了之后才执行
// deferredImportSelector表示推迟的ImportSelector,正常的ImportSelector是在解析配置类的过程中执行的
this.deferredImportSelectorHandler.process();
}
1.6 处理@ImportResource注解
@ImportResource可以用于导入spring的xml文件,然后解析xml文件生成定义的bean
如果配置类有@ImportResource注解,则获取指定的值,@ImportResource支持占位符填充,所以拿到注解指定的值之后,调用resolveRequiredPlaceholders()进行占位符解析,获取最终的资源名称,但此时并不会去直接解析xml文件,而是将其将其加入到当前配置类的importedResources中,后面再处理
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
1.7 处理@Bean注解方法
解析配置类中的@Bean方法,只是把这些方法找出来,然后封装成BeanMethon缓存在当前配置类的beanMethods属性总,并没有真正处理@Bean
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
通过ASM技术获取所有@Bean方法
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
// 上面这段注释的意思是,JVM反射所返回的方法顺序是任意的,直接取beanMethods做过测试,多运行几次确实是返回的方法顺序是不固定的
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
return beanMethods;
}
1.8 处理配置类所实现接口中的@Bean方法
解析配置类所实现的接口中的@Bean,但并没有真正处理@Bean,只是暂时找出来
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
递归遍历所有实现的接口,判断是否有@Bean方法,然后加入的当前配置类的BeanMethod属性中
/**
* Register default methods on interfaces implemented by the configuration class.
*/
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
processInterfaces(configClass, ifc);
}
}
1.9 返回配置类父类,循环解析
如果当前配置类有父类,则返回其父类,然后对父类进行解析,执行上面的流程
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/153655.html