微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

解读SpringBoot和SpringMVC中配置类的@Impot等导入是如何解析的

首先,给出答案,SpringBoot和SpringMVC中配置类的@Impot等导入是通过Spring中的invokebeanfactoryPostProcessors解析的

SpringBoot中的EnableAutoConfiguration是如何实现导入配置类的

在源码中我们可以看到,配置类应该是通过AutoConfigurationImportSelector和AutoConfigurationPackages.Registrar来导入的。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = \"spring.boot.enableautoconfiguration\";

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    String[] excludeName() default {};

}

AutoConfigurationPackages.Registrar是通过实现ImportBeanDeFinitionRegistrar接口来实现导入的

    static class Registrar implements ImportBeanDeFinitionRegistrar, DeterminableImports {

        @Override
        public void registerBeanDeFinitions(AnnotationMetadata Metadata, BeanDeFinitionRegistry registry) {
            register(registry, new PackageImport(Metadata).getPackageName());
        }

        @Override
        public Set<Object> determineImports(AnnotationMetadata Metadata) {
            return Collections.singleton(new PackageImport(Metadata));
        }

    }

AutoConfigurationImportSelector 是通过实现ImportSelector接口实现selectImports方法来实现的。但是我比较奇怪的是selectImports方法何时被调用,才能使得配置类被加入到IOC容器中
经过断点发现
主要进过了这么几个步骤
AbstractApplicationContext#refresh --> AbstractApplicationContext#invokebeanfactoryPostProcessors--> PostProcessorRegistrationDelegate#invokebeanfactoryPostProcessors -->iinvokeBeanDeFinitionRegistryPostProcessors#nvokeBeanDeFinitionRegistryPostProcessors(这个方法中遍历了所有bean后置处理器)-->ConfigurationClasspostProcessor#postProcessBeanDeFinitionRegistry-->ConfigurationClasspostProcessor#processConfigBeanDeFinitions
观察到这个接口之后可以看到

    /**
     * Build and validate a configuration model based on the registry of
     * {@link Configuration} classes.
     */
    public void processConfigBeanDeFinitions(BeanDeFinitionRegistry registry) {
        List<BeanDeFinitionHolder> configCandidates = new ArrayList<>();
        String[] candidateNames = registry.getBeanDeFinitionNames();

        for (String beanName : candidateNames) {
            BeanDeFinition beanDef = registry.getBeanDeFinition(beanName);
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                    ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                if (logger.isDebugEnabled()) {
                    logger.debug(\"Bean deFinition has already been processed as a configuration class: \" + beanDef);
                }
            }
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.MetadataReaderFactory)) {
                configCandidates.add(new BeanDeFinitionHolder(beanDef, beanName));
            }
        }

        // Return immediately if no @Configuration classes were found
        if (configCandidates.isEmpty()) {
            return;
        }

        // Sort by prevIoUsly determined @Order value, if applicable
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getorder(bd1.getBeanDeFinition());
            int i2 = ConfigurationClassUtils.getorder(bd2.getBeanDeFinition());
            return Integer.compare(i1, i2);
        });

        // Detect any custom bean name generation strategy supplied through the enclosing application context
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet) {
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONfigURATION_BEAN_NAME_GENERATOR);
                if (generator != null) {
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }

        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }

        // Parse each @Configuration class
        ConfigurationClassparser parser = new ConfigurationClassparser(
                this.MetadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        Set<BeanDeFinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            parser.parse(candidates);//核心代码
            parser.validate();

            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            configClasses.removeAll(alreadyParsed);

            // Read the model and create bean deFinitions based on its content
            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.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();
        }
    }

经过层层代码查找之后可以找到最终实现引入的代码

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 = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                        ParserStrategyUtils.invokeAwareMethods(
                                selector, this.environment, this.resourceLoader, this.registry);
                        if (selector instanceof DeferredImportSelector) {//引入实现了DeferredImportSelector接口的类
                            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 =
                                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(
                        \"Failed to process import candidates for configuration class [\" +
                        configClass.getMetadata().getClassName() + \"]\", ex);
            }
            finally {
                this.importStack.pop();
            }
        }
    }

即SpringBoot中EnableAutoConfiguratio两种获取配置类的方式,最后均归一到这一个方法中实现了引入到IOC容器中。

欢迎搜索关注本人与朋友共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐