首页 > 编程语言 > 详细

SpringBoot自动装配之我见

时间:2020-12-14 14:41:00      阅读:21      评论:0      收藏:0      [点我收藏+]

  网上很多文章对于自动状态都是说的很含糊,而且是千篇一律。很多都是这个注解@EnableAutoConfiguration就自动完成了。怎么可能呢?注解永远都是死的,是需要某个代码去解析处理的

  我今天就跟了下代码看看怎么回事

一  Configuration

  @Configuration这个注解从Spring3就有了,可不是一个新东西。他的作用就是解放配置文件。

  我们可以看到 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

  就是一个@Configuration。

  再看看 EnableAutoConfiguration,里面包含了一个 @Import

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

二  跟代码

  我们要分析的代码入口在  ConfigurationClassPostProcessor 。确切的说是  ConfigurationClassParser.parse 

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        this.deferredImportSelectors = new LinkedList<>();

        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                if (bd instanceof AnnotatedBeanDefinition) {
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
                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);
            }
        }

        processDeferredImportSelectors();//对AutoConfigurationImportSelector的解析在这里
    }

  继续往里面看 还是在  ConfigurationClassParser 

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

        // Recursively process any member (nested) classes first
        processMemberClasses(configClass, sourceClass);

        // Process any @PropertySource annotations
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), PropertySources.class,
                org.springframework.context.annotation.PropertySource.class)) {
            if (this.environment instanceof ConfigurableEnvironment) {
                processPropertySource(propertySource);
            }
            else {
                logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }

        // Process any @ComponentScan annotations
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() &&
                !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            for (AnnotationAttributes componentScan : componentScans) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

        // Process any @Import annotations
        processImports(configClass, sourceClass, getImports(sourceClass), true);

  注意绿色的注解,processImports专门负责解析 @Import

  我们直接跳到  processDeferredImportSelectors 

private void processDeferredImportSelectors() {
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;//见截图
        this.deferredImportSelectors = null;
        if (deferredImports == null) {
            return;
        }

        deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
        Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
        Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
        for (DeferredImportSelectorHolder deferredImport : deferredImports) {
            Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
            DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
                    (group == null ? deferredImport : group),
                    (key) -> new DeferredImportSelectorGrouping(createGroup(group)));
            grouping.add(deferredImport);
            configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                    deferredImport.getConfigurationClass());
        }
        for (DeferredImportSelectorGrouping grouping : groupings.values()) {
            grouping.getImports().forEach((entry) -> {
                ConfigurationClass configurationClass = configurationClasses.get(
                        entry.getMetadata());
                try {
                    processImports(configurationClass, asSourceClass(configurationClass),
                            asSourceClasses(entry.getImportClassName()), false);
                }

  技术分享图片

  在这里有两个对象一个是我们写main方法所在的bean就是用@SpringBootApplication注解的bean,另一个就是AutoConfigurationImportSelector

  所以自动装配发生作用的地点是在 ConfigurationClassPostProcessor 这个BeanFactoryPostProcessor对于注解@Configuration的处理中完成的

  本篇只分析到这里,对于AutoConfigurationImportSelector的详细调用过程,留到下一篇

  

SpringBoot自动装配之我见

原文:https://www.cnblogs.com/juniorMa/p/14132352.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!