栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ImportBeanDefinitionRegistrar作用原理介绍

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 imports, Set 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 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 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 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 registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry));
	}

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/643754.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号