spring-源码-@Import

前言

  • 导入jar包中的类,交由 spring 容器所管理
  • 我这里会用 Demo 中的 类名作为说明!!!,具体到了哪一步哪一步扫描谁,处理谁直接用类名 来表示,要是看的模糊的看一下类名

为什么使用@ Import

在平时的业务开发当中,将对象放入容器,使用 @Bean@Component基本就能够满足需求,但是@ Import注解能够方便扩展功能,其实我觉得可以认为是一个插件一样的东西,简简单单的只需要加上这个注解就能开启功能,

例如:

我现在想要让我们的项目拥有开飞机的功能,单单开飞机就可能需要很多组件,这些组件必须存在,这个项目才能开飞机,那如果毎一个类上都加上 @Component注解,到时候我不想要这个项目拥有开飞机功能,那是不是需要逐一的删除~~@Component~~注解,这时@Import的注解就体现出来了,我只需要自定义一个注解@Enable飞机,将飞机组件都加入到@import里面,需要的时候只需要将 @Enable飞机飞机加到个@Configuration注解里面就好了

所需知识

指的是你需要对这些稍微有一个了解,最起码稍微知道一点里面的属性…,当然不知道也没问题.

  1. BeanDefinition
  2. ConfigurationClass
  3. SourceClass

@Import

@ComponentScan("vip.xjdai.annotation.Import.annotation")
public class ImportContext {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportContext.class);
    }
}
 
@Configuration
@Import({ImportBean.class})
public class ImportConfiguration {}
// 假设这个 类 是一个jar 中的类,我们无法修改,但是又想让他被spring所管理如何做呢~那就利用 `@Import`注解好了
public class ImportBean {
}
 

注册@Configuration类

  1. new AnnotationConfigApplicationContext() 构造函数
  2. refresh() 刷新容器
  3. 执行 BeanFactoryPostProcessors,简单说是初始化一些 BeanFactoryPostProcessors
  4. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(); 执行BeanFactoryPostProcessors,简单说是初始化一些BeanFactoryPostProcessors
  5. 执行ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法
  6. 执行processConfigBeanDefinitions()–对package下的所有Classs 进行扫描预解析成BeanDefinition
  7. parse() --> parse() 进行解析—这里是处理@ComponentScan
  8. processConfigurationClass()
  9. doProcessConfigurationClass()
protected final SourceClass doProcessConfigurationClass(
    ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
    throws IOException {
 
    // 需要说明的是第一次扫描是将 `ImportConfiguration`放入到容器里面去,并不会将 `ImportConfiguration` 放入到容器中
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        // 循环所有 @ComponentScan
        for (AnnotationAttributes componentScan : componentScans) {
            // 去解析,去扫描所有符合条件的 Bean 并将其包装成 ScannedGenericBeanDefinition
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            //  循环所有 BeanDefinitionHolder
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                // 获取原始的 BeanDefinitionHolder
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                // 如果是NUll
                if (bdCand == null) {
                    // 将自身返回
                    bdCand = holder.getBeanDefinition();
                }
                // 检查是不是  @Configuration 、@Component、@ComponentScan、@Import、@ImportResource 注解,如果是则会进行递归~~~
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }
}
  • 需要说明的是第一次扫描是将 ImportConfiguration放入到容器里面去,并不会将 ImportConfiguration 放入到容器中
  • 第一次递归也是将扫描好的 ImportConfiguration包装成BeanDefinition,判断是不是 一些特定注解,由于我们的 Bean(ImportConfiguration)就是@Configuration ,所以条件符合那就进行递归调用

扫描@Import

  • 这里是接着上面讲的递归,也就是如果判断是不是 一些特定注解才掉的这个方法,
protected final void parse(@Nullable String className, String beanName) throws IOException {
    
    // 通过className 解析成 MetadataReader 对象 ,也就是元数据,这里的代码我就不贴了.. 简单来说我们传递一个Class 帮我们做了一些解析
    MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
    
    //重新构建了一个 ConfigurationClass 对象
    processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}
  • processConfigurationClass()

我精简了大量的代码,

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
    // 获取 SourceClass 这里是通过 Class 或者 ClassName 去获取 SourceClass(感兴趣自己去看一下吧)
    SourceClass sourceClass = asSourceClass(configClass, filter);
    do {
        // 去处理 Configuration 相关的类,
        sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
    }
    while (sourceClass != null);
    //添加到configurationClasses中
    this.configurationClasses.put(configClass, configClass);
}
  • doProcessConfigurationClass() – 这里的代码我只贴了核心的,其他的都不符合条件全删了…
protected final SourceClass doProcessConfigurationClass(
    ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
    throws IOException {
    // 这里处理  @Import 
    // getImports() 去获取  ImportConfiguration 这个类上 @Import 注解
    processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
    return null;
}
  • getImports()
    private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
        Set<SourceClass> imports = new LinkedHashSet<>();
        Set<SourceClass> visited = new LinkedHashSet<>();
        collectImports(sourceClass, imports, visited);
        return imports;
    }
  • collectImports

这里有一个递归的动作,等方法结束后都会去调用 imports.addAll()

private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
    throws IOException {
	
    if (visited.add(sourceClass)) {
        // 循环 目标类 上所有注解,也包括注解上的所有注解,会将其包装成SourceClass
        for (SourceClass annotation : sourceClass.getAnnotations()) {
            // 获取注解名称
            String annName = annotation.getMetadata().getClassName();
            // 如果不是 Import 则进行下一次循环,
            // 简单说判断了是不是包装成 Import了 比如很多@Enable***
            if (!annName.equals(Import.class.getName())) {
                // 进行递归,比如 @Enable***
                collectImports(annotation, imports, visited);
            }
        }
        //获取 @Import 注解上的属性,将其包装成 SourceClass  放入到集合当中
        imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    }
}
  • getAnnotationAttributes
public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
    
    // 根据注解的 Name 获取到所有的属性 
    Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
    
    // 属性如果是空则返回一个空,
    // 如果没有包含这个属性 也会返回一个空
    if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
        return Collections.emptySet();
    }
    // 获取属性获取 ClassName  简单说获取的就是 ImportBean 的全限定类名
    String[] classNames = (String[]) annotationAttributes.get(attribute);
    Set<SourceClass> result = new LinkedHashSet<>();
    // 循环所有的ClassName
    for (String className : classNames) {
        // getRelated() 就是根据 className 获取其Class 并且会包装成 SourceClass
        result.add(getRelated(className));
    }
    return result;
}

处理@Import

  1. 会先通过 getImports() 获取 @Import 注解要导入的类
  2. 会将 ImportBean 认为是一个 @Configuration继续递归一遍…
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                            boolean checkForCircularImports) {

    //判断 有没有 @Import  --这里的集合就是通过 getImports() 这个方法处理的
    if (importCandidates.isEmpty()) {
        return;
    }
	
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    } else {
        this.importStack.push(configClass);
        try {
            // 循环所有 @import 注解中的 Class 此时我们的 Class 是 `ImportBean`
            for (SourceClass candidate : importCandidates) {
                //判断 目标类 是不是实现了这个接口的
                if (candidate.isAssignable(ImportSelector.class)) {
                   	// 这里我暂时不说明,下面会有说明 
                } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // 这里我暂时不说明,下面会有说明 
                } else {
                    //  由于 既不是一个 ImportSelector、ImportBeanDefinitionRegistrar
                    //  则会 认为是一个 @Configuration....然后有会进行递归....
                    //  加入到  importStack 里面
                    this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    // 调用 processConfigurationClass
                    // 继续递归...进行处理,注意一下 candidate.asConfigClass(configClass)
                    // 也就说会重新构建一个 ConfigurationClass(),然后进行递归,当递归结束,就会放入到Map中
                    processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                }
            }
        } 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();
        }
    }
}
  • asConfigClass

需要说明的是,当前的 this 是 ImportBean 而 importedBy 是 ImportConfiguration

public ConfigurationClass asConfigClass(ConfigurationClass importedBy) {
    if (this.source instanceof Class) {
        return new ConfigurationClass((Class<?>) this.source, importedBy);
    }
    //这里是重新改造了一个 ConfigurationClass
    return new ConfigurationClass((MetadataReader) this.source, importedBy);
}
  • new ConfigurationClass()

主要是将 ImportConfiguration 放入到集合当中,然后结束后放入Map中

public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
    this.metadata = metadataReader.getAnnotationMetadata();
    this.resource = metadataReader.getResource();
    // 将标注有 `@Import()` 注解的目标类,放到这个集合当中去... 这里后面会用到
    this.importedBy.add(importedBy);
}

处理(组件)

  1. doProcessConfigurationClass() 这里是对 ImportBean的处理
  2. doProcessConfigurationClass这个方法走完
  3. 将其放入到 this.configurationClasses.put(configClass, configClass);
  4. 递归结束,也就是说结束了(组件的处理)这里我们可以简单的认为是对 ImportBean处理结束~

问题

我们知道了,在扫描的时候会吧ImportBean放入到Map中,那什么时候注册到容器中去的呢

我们假设所有流程走完了也就是说后面会去处理…

注册(组件)

  1. new AnnotationConfigApplicationContext() 构造函数
  2. refresh() 刷新容器
  3. 执行BeanFactoryPostProcessors(); 简单说是初始化一些BeanFactoryPostProcessors
  4. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(); 执行BeanFactoryPostProcessors,简单说是初始化一些BeanFactoryPostProcessors
  5. 执行ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry() 方法
  6. 执行processConfigBeanDefinitions()----这个方法还没执行完呢~~~
  7. parse()–方法出栈
  8. parse() --方法出栈
  9. processConfigurationClass()–方法出栈
  10. doProcessConfigurationClass()–方法出栈
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
 
    // 存放所有的 @Component、 @ComponentScan、@Import、@ImportResource、@Bean、Configuration类,需要注意的是这里的存放是已经注册过的..
    // 那我们知道,其实这个方法还在初始化呀,在初始化的时候只会帮我们装载了 @ComponentScan 的对象,这里不深究..
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    // alreadyParsed 用于判断是否处理过
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 
    do {
        // 去处理
        parser.parse(candidates);
        //校验
        parser.validate();
        // 这里是由 parser.getConfigurationClasses() 是在执行完 parse-->parse-->processConfigurationClass 执行完放进去滴~~
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);
 
        // 如果 reader是空就new 一个处理
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // 这里重点~~~ 开始加载啦
        this.reader.loadBeanDefinitions(configClasses);
        //然后标示这些已经处理~~
        alreadyParsed.addAll(configClasses);
        // 清除 candidates 集合,
        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            for (String candidateName : newCandidateNames) {
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                        !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());
    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }
 
    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // Clear cache in externally provided MetadataReaderFactory; this is a no-op
        // for a shared cache since it'll be cleared by the ApplicationContext.
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

调用loadBeanDefinitions

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    // 循环 所有的 ConfigurationClass 
    for (ConfigurationClass configClass : configurationModel) {
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}

调用loadBeanDefinitionsForConfigurationClass

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;
    }
    // 判断是否存在 imported 这里上面已经详细分析过了.
    if (configClass.isImported()) {
        //现在的关注点是这里
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    // 遍历配置类上所有的@Bean方法返回的bean并注册
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    // 导入资源配置如:@ImportResource(locations={"classpath:spring-beans.xml"}
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    // 这个地方下面在细谈~~
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

调用 registerBeanDefinitionForImportedConfigurationClass

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
    // 获取元数据
    AnnotationMetadata metadata = configClass.getMetadata();
    // 将元数据包装成 AnnotatedGenericBeanDefinition
    AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
    // 解析其 @Scope
    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
    configBeanDef.setScope(scopeMetadata.getScopeName());
    // 生成BeanName
    String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
    AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
    // 将 Name 和 AnnotatedGenericBeanDefinition 进行封装
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
    // 根据 @Scope 是否进行代理
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    // 进行注册,这里的注册也就是说是注册 我们的(组件)
    this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
    // 将Name 设置一下
    configClass.setBeanName(configBeanName);
}

流程图

在这里插入图片描述

ImportSelector

@ComponentScan
public class ImportSelectorContext {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportSelectorContext.class);
    }
}

class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{ImportBeanA.class.getName(), ImportBeanB.class.getName()};
    }
}

@Import({MyImportSelector.class})
@Configuration
class ImportConfiguration {
}

class ImportBeanB {
}

class ImportBeanA {
}

注册@Configuration类

跟 @import 基本一直

扫描@Import

跟 @import 基本一直

protected final SourceClass doProcessConfigurationClass(
    ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
    throws IOException {
    // 这里处理  @Import 因为 ImportConfiguration 这个类上有这个注解
    // 1. 会先通过 getImports() 获取有没有 @Import注解
    processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
    return null;
}
  • getImports() ,通过这个方法获取到 MyImportSelector
    private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
        Set<SourceClass> imports = new LinkedHashSet<>();
        Set<SourceClass> visited = new LinkedHashSet<>();
        collectImports(sourceClass, imports, visited);
        return imports;
    }

处理@Import

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                            boolean checkForCircularImports) {
    //判断 有没有 Import
    if (importCandidates.isEmpty()) {
        return;
    }
 
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    } else {
        this.importStack.push(configClass);
        try {
            // 循环所有 import
            for (SourceClass candidate : importCandidates) {
                //判断是不是实现了这个接口的
                if (candidate.isAssignable(ImportSelector.class)) {
                    // 获取到目标类~~
                    Class<?> candidateClass = candidate.loadClass();
                    //  去创建这个类,利用反射
                    ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                                                                   this.environment, this.resourceLoader, this.registry);
                   //  去执行 exclusion 方法,排除方法,可自行演示
                    Predicate<String> selectorFilter = selector.getExclusionFilter();
                    if (selectorFilter != null) {
                        exclusionFilter = exclusionFilter.or(selectorFilter);
                    }
                    //如果当前类是 DeferredImportSelector 的实现,则加入到 deferredImportSelectors
                    if (selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    } else {
                        //如果不是, 则调用  processImports 进行处理,也就是我们实现的那个类~~~
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        // 将 其包装成 SourceClass 然后进行递归..
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                       
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                    //判断是不是实现这个接口的
                } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // 省略~~~
                } else {
                    // 省略这里上面 讲过了
                }
            }
        }  catch (Throwable ex) {
        }
    }
}
  1. 当执行完 selectImports() 这个方法后,就获取到两个类的Class 全限定类名
    1. 这个方法的实现是由 我们自己定义的 MyImportSelector 的实现
  2. 然后去调用 asSourceClasses 执行完这个方法后, 会将 我们的类 包装成 SourceClass
  3. 然后执行递归 processImports
  4. 执行递归的时候,如果 我们定义的 BeanA 和BeanA 有实现 ImportBeanDefinitionRegistrar 或者 ImportSelector 的时候又会走一边,反正最终会走到 else 里面,也就说最终会将其认为是一个Configuration 类,执行一边,然后流程嘛就跟上面的差不多了…

创建(组件)

指的是@Import("")导入的组件什么时候创建对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZMvCYDZi-1597830774884)(//img.xjdai.vip/202007231724_452.png)]

后续处理

  1. 递归 processImports ,需要注意的是 importSourceClasses 是有2个类的,是我们添加到 String[]{}两个类
  2. 然后会走到 processConfigurationClass,对 importBeanAimportBeanB也就是说会递归两次~
  3. 然后将这两Map放到集合当中去

注册

  1. new AnnotationConfigApplicationContext() 构造函数
  2. refresh() 刷新容器
  3. 执行BeanFactoryPostProcessors(); 简单说是初始化一些BeanFactoryPostProcessors
  4. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(); 执行BeanFactoryPostProcessors,简单说是初始化一些BeanFactoryPostProcessors
  5. 执行ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry() 方法
  6. 执行processConfigBeanDefinitions()
  7. loadBeanDefinitions() – 注册
private void loadBeanDefinitionsForConfigurationClass(
    ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    // 是不是 Imported 的组件
    if (configClass.isImported()) {
        //注册 组件
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
}

ImportBeanDefinitionRegistrar

//定义配置类
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class ImportBeanDefinitionRegistrarConfig {}
 
//定义注册类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //importingClassMetadata 当前类的元数据
        //        registry.containsBeanDefinition() //判断容器中是否有这个Bean
        //        registry.getBeanDefinition() //根据名字获取 BeanDefinition
        registry.registerBeanDefinition("aaa", new RootBeanDefinition(ImportBeanDefinitionRegistrarBeanDemoA.class));// 注册一个Bean
    }
}
// 定义要被注册的类
public class ImportBeanA {
}

注册@Configuratio

跟最开始的基本一致

扫描@Import

跟最开始的基本一致

处理@Import

这里的处理可以认为是处理MyImportBeanDefinitionRegistrar我们自定义的类

  1. 会先通过 getImports() 获取有没有 @Import 注解
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                            boolean checkForCircularImports) {
    //判断 有没有 Import
    if (importCandidates.isEmpty()) {
        return;
    }
 
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    } else {
        this.importStack.push(configClass);
        try {
            // 循环所有 import
            for (SourceClass candidate : importCandidates) {
                //判断是不是实现了这个接口的
                if (candidate.isAssignable(ImportSelector.class)) {
                    // 省略~~
                } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // 也就是说 通过 ImportBeanDefinitionRegistrar 来创建 了这个 Bean
                    Class<?> candidateClass = candidate.loadClass();
                    //去 实例化 这个对象
                    ImportBeanDefinitionRegistrar registrar =
                        ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                                             this.environment, this.resourceLoader, this.registry);
                    // 放入到一个 importBeanDefinitionRegistrars Map 中去~~~
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                } else {
                   // 省略~~
                }
            }
        }  catch (Throwable ex) {
        }
    }
}

创建(组件)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wp3VZEeV-1597830774890)(//img.xjdai.vip/202007240934_128.png)]

组件注册

  1. new AnnotationConfigApplicationContext() 构造函数
  2. refresh() 刷新容器
  3. 执行BeanFactoryPostProcessors(); 简单说是初始化一些BeanFactoryPostProcessors
  4. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(); 执行BeanFactoryPostProcessors,简单说是初始化一些BeanFactoryPostProcessors
  5. 执行ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry() 方法
  6. 执行processConfigBeanDefinitions()
  7. loadBeanDefinitions() – 注册
    private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
        // 这里是去注册实现了  ImportBeanDefinitionRegistrars 接口的
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }
  • registrar就是 MyImportBeanDefinitionRegistrar 这个类,这个类去调用这个接口
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    registrars.forEach((registrar, metadata) ->
                       registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
//接口内部做了一个实现 1.8特性~~
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
                                     BeanNameGenerator importBeanNameGenerator) {
    //真正的目标方法
    registerBeanDefinitions(importingClassMetadata, registry);
}

DeferredImportSelector

本类没有深入研究,就不写了,大致写一下

    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                                Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                                boolean checkForCircularImports) {

        //判断 有没有 @Import
        if (importCandidates.isEmpty()) {
            return;
        }

        if (checkForCircularImports && isChainedImportOnStack(configClass)) {
            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
        } else {
            this.importStack.push(configClass);
            try {
                // 循环所有 @import 注解中的 Class
                for (SourceClass candidate : importCandidates) {
                    //判断 目标类 是不是实现了这个接口的
                    if (candidate.isAssignable(ImportSelector.class)) {
                        // Candidate class is an ImportSelector -> delegate to it to determine imports
                        // 获取目标类的Class
                        Class<?> candidateClass = candidate.loadClass();
                        //  去创建 这个 目标类,利用反射
                        ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                this.environment, this.resourceLoader, this.registry);
                        Predicate<String> selectorFilter = selector.getExclusionFilter();
                        if (selectorFilter != null) {
                            exclusionFilter = exclusionFilter.or(selectorFilter);
                        }
                        //如果当前类是DeferredImportSelector 的实现,则加入到deferredImportSelectors
                        if (selector instanceof DeferredImportSelector) {
                            //  放入到一个集合当中去
                            this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                        } else {
                        	//省略
                        }
                        //判断是不是实现这个接口的
                    } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    //省略
                    } else {
                      //省略
                    }
                }
            } catch (BeanDefinitionStoreException ex) {
                throw ex;
            } catch (Throwable ex) {

            }
        }
    }

什么时候调用呢,我看到的在所有的

  1. new AnnotationConfigApplicationContext() 构造函数
  2. refresh() 刷新容器
  3. 执行 BeanFactoryPostProcessors,简单说是初始化一些 BeanFactoryPostProcessors
  4. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(); 执行BeanFactoryPostProcessors,简单说是初始化一些BeanFactoryPostProcessors
  5. 执行ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法
  6. 执行processConfigBeanDefinitions()–对package下的所有Classs 进行扫描预解析成BeanDefinition
  7. parse() – 在这个方法体里面结束后执行的
    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        //循环所有 BeanDefinitionHolder
        for (BeanDefinitionHolder holder : configCandidates) {
            // 获取 BeanDefinition
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 这里根据Bean定义的不同类型走不同的分支,但是最终都会调用到方法 processConfigurationClass(ConfigurationClass configClass)
                if (bd instanceof AnnotatedBeanDefinition) {
                    //将 元数据和Bean取出来
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                    //  如果是 AbstractBeanDefinition 并且存在 BeanClass 因为我们知道 有可能 BeanClass 是String类型
                } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
                } else {
                    // 如果上面判断都没过则就会走这里
                    parse(bd.getBeanClassName(), holder.getBeanName());
                }
            } catch (BeanDefinitionStoreException ex) {
                throw ex;
            } catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
            }
        }
        //  执行找到的 DeferredImportSelector
        //  DeferredImportSelector 是 ImportSelector 的一个变种。
        //  ImportSelector 被设计成其实和 @Import 注解的类同样的导入效果,
        //  但是实现 ImportSelector 的类可以条件性地决定导入哪些配置。
        //  DeferredImportSelector 的设计目的是在所有其他的配置类被处理后才处理。
        //  这也正是该语句被放到本函数最后一行的原因。
        this.deferredImportSelectorHandler.process();
    }
  • 也就是说是在最后一行执行的

后续说明

  • 其实只要读懂了 @import 也就说最开始的那个东东,后面的这些基本相差不是特别大…
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值