不要问我阅读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();
}
}
}