spring源码-ioc(四)-@import and @Bean 解析

455 阅读4分钟

不要问我阅读spring源码有什么用,问就是没有用,只是让我自己使用spring的过程中自信点!

相关文章

spring-相关文章

接上篇,直接上代码,上篇链接为spring-ioc(三)-ConfigurationClassPostProcessor

说明

@Import 真的很重要

作用

直接向beanDefinition注册bean,向beanDefinition中注册bean意味着我们可以操纵bean容器

用法

这个可能要先讲下用法

普通类

假如我有个类TestService 我没有把这个类交给spring管理(没有使用@Controller,@Service,@Bean....等相关的操作)

我们可以这样 @Import(TestService.class) 这样操作之后我们的这个bean也是在spring-ioc中的

ImportSelector

自己定义一个类实现ImportSelector接口
public class MyImportSelector implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		//这个数据中传我们需要交给spring-ioc管理的bean,是个数组
		return new String[] {"com.kiss.mxb.service.TestService"};
	}

}

ImportBeanDefinitionRegistrar

//自己定义一个类实现ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//这个地方就不写伪代码了,大概讲下作用
		//看到没我们重写的这个方法,拿到了两个参数
		//AnnotationMetadata 前面几篇文章假如看了的话,应该知道这个是注解元数据,就是一个类上面的所有注解
		//BeanDefinitionRegistry 注册器
		//我们拿到了注册器就可以所以的向spring-ioc注册bean,所有说这个功能很强大
		//我们不但可以拿到注册器,还拿到了注解元数据,那就意味着 假如我们这些注解的值中包含了一个包名,我们完全可以扫描这个包,然后注册到spring-ioc中去
		//mybatis 的 @MapperScan 就是这么做的
	}
}

//如下
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {}


如下
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {}

spring源码继续

继续看源码

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

..............................................上面的代码上节课应该讲过了,所以先删除掉......................................................................

	// Process any @Import annotations
	//我们本文的重点  处理
	//getImports() 这个方法是获取当前列上面的所有 @import注解导入的bean,下面会看下这个方法
	processImports(configClass, sourceClass, getImports(sourceClass), true);

	// 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);
		}
	}

	// Process individual @Bean methods
	//顺便说下,这个地方是处理@bean的
	//获取当前类里面所有被@bean注释 的方法
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
	    //循环 把这些方法 放到ConfigurationClass.beanMethods 属性里面
	    //注意 当前的bean和@import导入的bean一样,并没有被注册
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// Process default methods on interfaces
	processInterfaces(configClass, sourceClass);

	// 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();
		}
	}

	// No superclass -> processing is complete
	return null;
}
//获取@import 导入的bean
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())) {
			    //注意,这是个递归的方法,也就是说假如你注解上有注解里面存在@import 也是可以找到的
				collectImports(annotation, imports, visited);
			}
		}
		imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
	}
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
    //假如没有获取到 @improt 导入的bean 直接结束
	if (importCandidates.isEmpty()) {
		return;
	}
    //检查下 你的 当前类是否解析过
	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
	    //发你的当前类放入importStack  假如你现在是A bean A bean上面有个@import(MySelector.class)
	    //则 我说的当前类是 A  MySelector.class 为这个方法的参数importCandidates
		this.importStack.push(configClass);
		try {
		    循环
			for (SourceClass candidate : importCandidates) {
			    //如果是实现 ImportSelector
				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);
					//DeferredImportSelector 是继承了 ImportSelector
					//在springboot 的 @EnableAutoConfiguration 上面的import就是使用了 DeferredImportSelector
					if (selector instanceof DeferredImportSelector) {
						this.deferredImportSelectorHandler.handle(
								configClass, (DeferredImportSelector) selector);
					}
					else {
					    //实现了ImportSelector
					    //这里就是对应了上面的实例化  ImportSelector
					    //执行selectImports方法,还记得我们重写的方法吧,返回一个 string[]
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						//把你方法返回的bean 封装为 SourceClass
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
						//递归调用当前方法,直到走到 普通类的流程,最后把bean放入 ConfigurationClassParser.configurationClasses
						processImports(configClass, currentSourceClass, importSourceClasses, false);
					}
				}
				//如果是实现 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 =
							BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
					ParserStrategyUtils.invokeAwareMethods(
							registrar, this.environment, this.resourceLoader, this.registry);
					//调用重新方法,传递参数 注册器  注解元数据  拿到了注册器 和注解元数据,可以干自己想干的事情,功能很强大
					//这个地方,是把实现了ImportBeanDefinitionRegistrar的bean放在了importBeanDefinitionRegistrars容器中
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
				else {
					// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
					// process it as an @Configuration class
					//普通类
					//把导入的bean放到 imports
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					//这个地方,又去调用了 processConfigurationClass 方法,说明是递归处理
					//这个方法里面最后是降这个configClass 存放在 org.springframework.context.annotation.ConfigurationClassParser.configurationClasses
					//注意,这个时候还没有去注册
					//candidate.asConfigClass()这个方法挺重要,主要是为了表示当前导入的bean 是在哪个bean上面导入的
					//辨识字段为 importedBy  这字段名称起的也真是见名知意
					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();
		}
	}
}