spring(十一)----@Import

处理@Import分为3种:
1、ImportSelector:这种方式是返回一个字符串,由给定的字符串让spring去new一个类。然后动态添加BeanDefinition,这new这个过程无法参与。
2、ImportBeanDefinitionRegistrar:这种方式是将注册器给程序员,这样程序员就能动态的改变BeanDefinition,比前者权限更大。
3、普通类:这个没有什么特别的,这种方式不多赘述,跟ImportSelector比较相似。
我们直接到关键代码:
org.springframework.context.annotation.ConfigurationClassParser#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)) {//ImportSelector类型
						// 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);
						if (selector instanceof DeferredImportSelector) {//Deferred是延迟,表示后续处理
							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)) {//ImportBeanDefinitionRegistrar类型
						// 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());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						/**
						 * 否则,加入到importStack后调用processConfigurationClass 进行处理,processConfigurationClass里面主要就是把类放到configurationClasses
						 * configurationClasses是一个集合,会在后面拿出来解析成bd继而注册,可以看到普通类在扫描出来的时候就被注册了
						 * 如果是importSelector,会先放到configurationClasses后面进行出来注册
						 */
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				this.importStack.pop();
			}
		}
	}

这里我们写3个测试类讲解:

package com.test.MYImport;

public class MYcommon {
}

package com.test.MYImport;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MYImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {

	}

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

	}
}

package com.test.MYImport;

import com.test.dao.IndexDao3;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MYImportSeletor implements ImportSelector {
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return new String[]{IndexDao3.class.getName()};
	}
}

这3个就是3种import方式。至于@Import添加就自己去添加。
我们来看第一种情况ImportSelector:
在这里插入图片描述当进入这个判断之后就会拿到ImportSelector方法给的字符串,由这个字符串找到这个类,然后执行processImports方法递归调用,由于拿到的IndexDao3这个类是一个普通类,所以就放到importStack中,然后调用processConfigurationClass方法,这个方法最终将这个类存到configurationClasses这个map中,方便后面注册。
在这里插入图片描述第二种情况我们看ImportBeanDefinitionRegistrar方法:
最终调用configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());这个方法做的事情就是把它put到importBeanDefinitionRegistrars这个map中,方便后面注册。
在这里插入图片描述那么是在什么时候注册的呢?通过调试发现是在org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions中的this.reader.loadBeanDefinitions(configClasses);这行代码中,截图如下
在这里插入图片描述在这里插入图片描述从这里能够看出注册是这里注册的,那么这行代码做了什么呢?

	/**
	 * Read a particular {@link ConfigurationClass}, registering bean definitions
	 * for the class itself and all of its {@link Bean} methods.
	 */
	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()) {//注册selector
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
		//xml
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		//注册Registrar
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

注册selector这个方法就是spring内部根据规则设置了属性,程序员没法插手。
注册Registrar这个方法就是能够获得registry注册器,执行org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars

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

通过这个调用我们自己实现了ImportBeanDefinitionRegistrar方法的方式,因为这个方法可以得到BeanDefinitionregistry,所以能够动态添加BeanDefinition,也能够改变BeanDefinition,mybatis的mapperscan就是经典的应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值