ImportBeanDefinitionRegistrar作用原理介绍

介绍

简单的说,就是在spring应用启动过程,一些被@Import注解的类(这些类都实现了ImportBeanDefinitionRegistrar接口)会执行ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,然后生成BeanDefinition对象,并最终注册到BeanDefinitionRegistry中,为后续实例化bean做准备的。

在哪里用到了?

以我们非常熟悉的spring boot应用为例,启动类就包含了,
@SpringBootApplication注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    
    

其中@Import(AutoConfigurationImportSelector.class)就是。

另外还有spring集成mybatis的注解**@MapperScan**一样也用到。

使用过程解析

进入org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);

进去getImports方法

	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.startsWith("java") && !annName.equals(Import.class.getName())) {
    
    
					collectImports(annotation, imports, visited);
				}
			}
			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
		}
	}

这里的SourceClass是当前的配置类,什么是配置类?配置类就是包含@Configuration、@Service、@Component等注解的类,比如我们的spring boot启动类。

上面这段代码相当于是每个配置类都去找一遍是否包含@Import注解。

出来接着上面的processImports方法

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) {
    
    
					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);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
    
    
						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 {
    
    
						// 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));
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
    
    
				throw ex;
			}
			catch (Throwable ex) {
    
    
				throw new BeanDefinitionStoreException(
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
    
    
				this.importStack.pop();
			}
		}
	}

这里也很简单,就是几个if else分支判断,
其中
if(candidate.isAssignable(ImportBeanDefinitionRegistrar.class))
是不是看到ImportBeanDefinitionRegistrar接口了,这里就是把上面找到的Import类添加到
org.springframework.context.annotation.ConfigurationClass#importBeanDefinitionRegistrars这个Map中。

顺便说一下另外的
if (candidate.isAssignable(ImportSelector.class))这句就是我们熟悉用来解析spring boot自动装配用的,只不过它是ImportSelector类型,这种不放到Map中,后面会延迟单独处理它。

上面的查找过程,是每一个配置类都走一遍,如果有ImportBeanDefinitionRegistrar,就加到各自里面的Map先缓存起来。

既然存起来了,那肯定有用的地方是吧, 接着看。

先说明下ConfigurationClassPostProcessor这个类,很重要,它是解析所有配置类的,将配置类都转换成BeanDefinition对象,后续创建bean就靠它, 上面调用链路也是由它发起的。

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
其中有一句:
this.reader.loadBeanDefinitions(configClasses);

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    
    
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
    
    
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

遍历每一个ConfigurationClass 配置类,因为我们前面已经是解析过ImportBeanDefinitionRegistrar了,所以这些配置类是包含ImportBeanDefinitionRegistrar类的。

private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    
    

		if (trackedConditionEvaluator.shouldSkip(configClass)) {
    
    
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
    
    
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		if (configClass.isImported()) {
    
    
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    
    
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
好了,这里终于要拿前面缓存好的Map了

	private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    
    
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry));
	}

遍历每一个ImportBeanDefinitionRegistrar类,调用registerBeanDefinitions方法完成后续注册工作。

猜你喜欢

转载自blog.csdn.net/huangdi1309/article/details/121764438