美文网首页
spring的自动配置是怎么实现的(一)

spring的自动配置是怎么实现的(一)

作者: guessguess | 来源:发表于2020-07-10 15:06 被阅读0次

https://www.jianshu.com/p/faa1bfe0d11a
之前在做简易工具的时候发现一个问题。为什么把config里面的配置给配好,就可以完成注入呢?我们只是添加了rocketmq的依赖,此外也只是满足其RocketMQAutoConfiguration的依赖注入,随后什么都没做,为什么可以实现呢。究竟RocketMQAutoConfiguration是怎么被注入的

此时其实毫无思绪。
从启动类来看,并没有找到任何相关的处理

@SpringBootApplication
public class Config {
    public static void main(String args[]) {
        SpringApplication.run(Config.class, args);
    }
}

下面先看看SpringBootApplication注解的内部,看看有哪些注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
  。。。代码就补贴了
}

从代码上来看总共分为3个注解,分别为@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,从结构上来看,就是三个功能,@SpringBootConfiguration表明该类为springboot的配置类(其内部其实就是我们常用的@Configuration),@EnableAutoConfiguration则是开启自动装配,而@ComponentScan是进行扫描注入。

那么我们只需要关注@EnableAutoConfiguration这个注解是如何工作的了。
先看看其内部

/**
 * Enable auto-configuration of the Spring Application Context, attempting to guess and
 * configure beans that you are likely to need. Auto-configuration classes are usually
 * applied based on your classpath and what beans you have defined. For example, if you
 * have {@code tomcat-embedded.jar} on your classpath you are likely to want a
 * {@link TomcatServletWebServerFactory} (unless you have defined your own
 * {@link ServletWebServerFactory} bean).
 * <p>
 * When using {@link SpringBootApplication}, the auto-configuration of the context is
 * automatically enabled and adding this annotation has therefore no additional effect.
 * <p>
 * Auto-configuration tries to be as intelligent as possible and will back-away as you
 * define more of your own configuration. You can always manually {@link #exclude()} any
 * configuration that you never want to apply (use {@link #excludeName()} if you don't
 * have access to them). You can also exclude them via the
 * {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
 * after user-defined beans have been registered.
 * <p>
 * The package of the class that is annotated with {@code @EnableAutoConfiguration},
 * usually via {@code @SpringBootApplication}, has specific significance and is often used
 * as a 'default'. For example, it will be used when scanning for {@code @Entity} classes.
 * It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're
 * not using {@code @SpringBootApplication}) in a root package so that all sub-packages
 * and classes can be searched.
 * <p>
 * Auto-configuration classes are regular Spring {@link Configuration} beans. They are
 * located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).
 * Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
 * often using {@link ConditionalOnClass @ConditionalOnClass} and
 * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @see ConditionalOnBean
 * @see ConditionalOnMissingBean
 * @see ConditionalOnClass
 * @see AutoConfigureAfter
 * @see SpringBootApplication
 */
@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 {};

}

由于本人英文比较渣,看了一下注释,其实大概发现了点东西。
大概就是说这个注解只是作为自动装配用的,并不会有其他额外的影响。
另外就是自动装配还可以排除一些你不想要的配置类,使用exclude。
SpringFactoriesLoader用于定位自动装配的类。
被自动装配的配置类通常都是在用户定义的bean被注册之后才进行注册的。那么这里我想,应该是在configutationClassPostProcessor(因为扫描注入类,以及导入类的功能都是这里实现的)里面去处理,后面验证一下。
头部的@AutoConfigurationPackage注解暂时不知道是做什么用的,待会再看,先观察一下导入的AutoConfigurationImportSelector这个类具备什么作用。

先观察一下AutoConfigurationImportSelector这个类的结构。

public class AutoConfigurationImportSelector
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
        BeanFactoryAware, EnvironmentAware, Ordered {

    private static final String[] NO_IMPORTS = {};

    private static final Log logger = LogFactory
            .getLog(AutoConfigurationImportSelector.class);

    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

    private ConfigurableListableBeanFactory beanFactory;

    private Environment environment;

    private ClassLoader beanClassLoader;

    private ResourceLoader resourceLoader;
}

通过上述代码,大概可以知道,这个类总共实现了多个接口,DeferredImportSelector,BeanClassLoaderAware,ResourceLoaderAware,BeanFactoryAware,EnvironmentAware,Ordered。Ordered呢,主要用于排序,而xxAware接口,其实是用于设置各种spring的相关变量的,如bean工厂,资源加载器,bean的类加载器,环境。所以这里我们要关注的是DeferredImportSelector接口。

下面看看DeferredImportSelector接口的内部结构。

public interface DeferredImportSelector extends ImportSelector {

    /**
     * Return a specific import group or {@code null} if no grouping is required.
     * @return the import group class or {@code null}
     */
    @Nullable
    default Class<? extends Group> getImportGroup() {
        return null;
    }


    /**
     * Interface used to group results from different import selectors.
     */
    interface Group {

        /**
         * Process the {@link AnnotationMetadata} of the importing @{@link Configuration}
         * class using the specified {@link DeferredImportSelector}.
         */
        void process(AnnotationMetadata metadata, DeferredImportSelector selector);

        /**
         * Return the {@link Entry entries} of which class(es) should be imported for this
         * group.
         */
        Iterable<Entry> selectImports();

        /**
         * An entry that holds the {@link AnnotationMetadata} of the importing
         * {@link Configuration} class and the class name to import.
         */
        class Entry {

            private final AnnotationMetadata metadata;

            private final String importClassName;

            public Entry(AnnotationMetadata metadata, String importClassName) {
                this.metadata = metadata;
                this.importClassName = importClassName;
            }

            /**
             * Return the {@link AnnotationMetadata} of the importing
             * {@link Configuration} class.
             */
            public AnnotationMetadata getMetadata() {
                return this.metadata;
            }

            /**
             * Return the fully qualified name of the class to import.
             */
            public String getImportClassName() {
                return this.importClassName;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) {
                    return true;
                }
                if (o == null || getClass() != o.getClass()) {
                    return false;
                }
                Entry entry = (Entry) o;
                return Objects.equals(this.metadata, entry.metadata) &&
                        Objects.equals(this.importClassName, entry.importClassName);
            }

            @Override
            public int hashCode() {
                return Objects.hash(this.metadata, this.importClassName);
            }
        }
    }

}

public interface ImportSelector {

    /**
     * Select and return the names of which class(es) should be imported based on
     * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
     */
    String[] selectImports(AnnotationMetadata importingClassMetadata);

}

看了一下,没看出个所以然。
用简单粗暴的方式debug一下吧。
我们将断点定位在AutoConfigurationImportSelector的selectImports方法。看一下其执行的流程


截屏2020-07-09下午9.00.22.png

从上述图中,我们可以看到RocketMQAutoConfiguration的影子了。从上述代码执行的流程分析。这一步操作是在容器刷新的过程中执行的,刷新的时候会先执行beanDefinitionRegistoryProcessor的postProcessBeanDefinitionRegistry用于处理一些注册bean的逻辑。
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法比较主要。
1.找出所有的配置类
2.循环配置类
2.1通过配置类的@componentScan去扫描并且注册bean(通过@compoent注解)
2.2找出导入的bean,通过@import注解
2.3processDeferredImportSelectors---处理导入延时选择器

我们来看看configurationClassPostProcessor是怎么处理的

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

        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                 //这里肯定都是注解类型的bean,所以走第一个分支
                if (bd instanceof AnnotatedBeanDefinition) {
                    //这里面就涉及到如何解析类,就是上面的2.1,2.2
                    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);
            }
        }
        //延迟导入选择器的执行。。。为什么叫延迟?或许执行到这一步的时候,用户定义的bean已经被注册了,剩下的就是一些自动装配相关需要被注册的类。
        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 ? group : deferredImport),
                    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);
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to process import candidates for configuration class [" +
                            configurationClass.getMetadata().getClassName() + "]", ex);
                }
            });
        }
    }

原谅我口嗨了,这个方法我看不下去 = = 还是先解析一下对应的结构。
DeferredImportSelectorHolder
DeferredImportSelectorGrouping
AnnotationMetadata
DeferredImportSelector
先看看DeferredImportSelectorHolder的结构,就是一个内部类,封装了配置类以及延迟导入选择器

class ConfigurationClassParser {
    private static class DeferredImportSelectorHolder {

        private final ConfigurationClass configurationClass;

        private final DeferredImportSelector importSelector;

        public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
            this.configurationClass = configClass;
            this.importSelector = selector;
        }

        public ConfigurationClass getConfigurationClass() {
            return this.configurationClass;
        }

        public DeferredImportSelector getImportSelector() {
            return this.importSelector;
        }
    }
}

再看看DeferredImportSelectorGrouping的结构,发现该变量封装了一个接口类型的变量group,以及DeferredImportSelectorHolder(一个封装ConfigurationClass以及DeferredImportSelector)的变量

class ConfigurationClassParser {
    private static class DeferredImportSelectorGrouping {

        private final DeferredImportSelector.Group group;

        private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();

        DeferredImportSelectorGrouping(Group group) {
            this.group = group;
        }

        public void add(DeferredImportSelectorHolder deferredImport) {
            this.deferredImports.add(deferredImport);
        }

        /**
         * Return the imports defined by the group.
         * @return each import with its associated configuration class
         */
        public Iterable<Group.Entry> getImports() {
            for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                        deferredImport.getImportSelector());
            }
            return this.group.selectImports();
        }
    }
}

另外顺便看看DeferredImportSelector.Group的结构,代码如下,看起来这个类相对简单,有一个process(注解元信息,延迟导入选择器)方法,另外还有一个内部的类Entry,封装了元数据以及导入的类名称。

class ConfigurationClassParser {
/**
     * Interface used to group results from different import selectors.
     */
    interface Group {

        /**
         * Process the {@link AnnotationMetadata} of the importing @{@link Configuration}
         * class using the specified {@link DeferredImportSelector}.
         */
        void process(AnnotationMetadata metadata, DeferredImportSelector selector);

        /**
         * Return the {@link Entry entries} of which class(es) should be imported for this
         * group.
         */
        Iterable<Entry> selectImports();

        /**
         * An entry that holds the {@link AnnotationMetadata} of the importing
         * {@link Configuration} class and the class name to import.
         */
        class Entry {

            private final AnnotationMetadata metadata;

            private final String importClassName;

            public Entry(AnnotationMetadata metadata, String importClassName) {
                this.metadata = metadata;
                this.importClassName = importClassName;
            }

            /**
             * Return the {@link AnnotationMetadata} of the importing
             * {@link Configuration} class.
             */
            public AnnotationMetadata getMetadata() {
                return this.metadata;
            }

            /**
             * Return the fully qualified name of the class to import.
             */
            public String getImportClassName() {
                return this.importClassName;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) {
                    return true;
                }
                if (o == null || getClass() != o.getClass()) {
                    return false;
                }
                Entry entry = (Entry) o;
                return Objects.equals(this.metadata, entry.metadata) &&
                        Objects.equals(this.importClassName, entry.importClassName);
            }

            @Override
            public int hashCode() {
                return Objects.hash(this.metadata, this.importClassName);
            }
        }
    }
}

看完上面的类的结构我们回到configurationClassPostProcessor

    private void processDeferredImportSelectors() {
        //先从成员变量中获取延迟导入选择器的包装信息
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        //切断引用,这里不知道为何要这么做
        this.deferredImportSelectors = null;
        //若没有任何的延迟导入选择器,则不进行任何处理
        if (deferredImports == null) {
            return;
        }
        //先根据比较器进行排序,这里如何比较就不是重点了,先跳过
        deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
        //用于保存DeferredImportSelectorGrouping分组的信息,key可能是class对象也可以DeferredImportSelector
        Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
        Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
        for (DeferredImportSelectorHolder deferredImport : deferredImports) {
            //获取延迟导入选择器对应的组的信息,通过debug发现,spring只有AutoConfigurationImportSelector这个类实现了getImportGroup方法返回AutoConfigurationGroup.class,若没有被实现则返回空,一开始deferredImports只有AutoConfigurationImportSelector,所以的话group是不会为空的
            Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup(); 
            //groupings-> 这里会生成AutoConfigurationGroup对应的延迟导入选择器的group
            DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
                    (group != null ? group : deferredImport),
                    key -> new DeferredImportSelectorGrouping(createGroup(group)));
            //同时将导入选择器加入对应的组中,组里面有一个List<DeferredImportSelectorHolder>,用于保存该组对应的导入选择器列表
            grouping.add(deferredImport);
            configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                    deferredImport.getConfigurationClass());
        }
        //对延迟选择器组进行遍历
        for (DeferredImportSelectorGrouping grouping : groupings.values()) {
            //取出该组中对应对的延迟导入选择器holder,然后进行处理,那么如何获取到需要被自动装配的配置类呢?那么只能是在grouping.getImports()方法中去实现。所以重点还是grouping.getImports()方法。那么下面重点看看这个方法的实现。
            grouping.getImports().forEach(entry -> {
                ConfigurationClass configurationClass = configurationClasses.get(entry.getMetadata());
                try {
                    //对每个自动装配的configuration进行处理,这个方法内部最终走到的还是,ConfigurationClassParser的processConfigurationClass(ConfigurationClass configClass)方法,就是如何去处理配置类的相关逻辑,这里其实我们不用去关心,无法就是去处理改配置类相关的一些注入,如@import,@componentScan
                    processImports(configurationClass, asSourceClass(configurationClass),
                            asSourceClasses(entry.getImportClassName()), false);
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to process import candidates for configuration class [" +
                            configurationClass.getMetadata().getClassName() + "]", ex);
                }
            });
        }
    }

getImports方法的实现如下

class ConfigurationClassParser {
    private static class DeferredImportSelectorGrouping {

        private final DeferredImportSelector.Group group;

        private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();

        DeferredImportSelectorGrouping(Group group) {
            this.group = group;
        }

        public void add(DeferredImportSelectorHolder deferredImport) {
            this.deferredImports.add(deferredImport);
        }

        /**
         * Return the imports defined by the group.
         * @return each import with its associated configuration class
         */
        //从这个方法中我们可以得出,最后还是交给Group来处理的,而我们需要关注的group只有AutoConfigurationGroup,所以看看AutoConfigurationGroup的process方法
        public Iterable<Group.Entry> getImports() {
            for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                        deferredImport.getImportSelector());
            }
            return this.group.selectImports();
        }
    }
}

AutoConfigurationGroup的process方法,代码如下

public class AutoConfigurationImportSelector
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
        BeanFactoryAware, EnvironmentAware, Ordered {

    private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
            BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {

        private ClassLoader beanClassLoader;

        private BeanFactory beanFactory;

        private ResourceLoader resourceLoader;

        private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();

        @Override
        public void setBeanClassLoader(ClassLoader classLoader) {
            this.beanClassLoader = classLoader;
        }

        @Override
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }

        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }

        @Override
        public void process(AnnotationMetadata annotationMetadata,
                DeferredImportSelector deferredImportSelector) {
            //通过延迟导入选择器,找出所有需要被导入的类,从例子中我们得中,其实传入的选择器就是AutoConfigurationImportSelector,所以关注这个类的selectImports方法即可。
            String[] imports = deferredImportSelector.selectImports(annotationMetadata);
            for (String importClassName : imports) {
                this.entries.put(importClassName, annotationMetadata);
            }
        }

        @Override
        public Iterable<Entry> selectImports() {
            return sortAutoConfigurations().stream()
                    .map((importClassName) -> new Entry(this.entries.get(importClassName),
                            importClassName))
                    .collect(Collectors.toList());
        }

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //到了这里才是最后返回configurations集合的关键,往里面走
        List<String> configurations = getCandidateConfigurations(annotationMetadata,
                attributes);
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return StringUtils.toStringArray(configurations);
    }

    /**
     * Return the auto-configuration class names that should be considered. By default
     * this method will load candidates using {@link SpringFactoriesLoader} with
     * {@link #getSpringFactoriesLoaderFactoryClass()}.
     * @param metadata the source metadata
     * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
     * attributes}
     * @return a list of candidate configurations
     */
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        //再往里面走。。。
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
        Assert.notEmpty(configurations,
                "No auto configuration classes found in META-INF/spring.factories. If you "
                        + "are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
}

继续往里面走,最后定位到SpringFactoriesLoader,那么看看其内部执行

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            //到最后就是通过类加载器,将所有的META-INF/spring.factories资源给找出来
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                //加载spring.factories资源
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    List<String> factoryClassNames = Arrays.asList(
                            StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
                    //key=org.springframework.boot.autoconfigure.EnableAutoConfiguration
                    //value的话 就是对应的若干个configuration
                    result.addAll((String) entry.getKey(), factoryClassNames);
                }
            }
            //随后放入缓存,其实后续通过类加载器,从缓存中取就好了,避免没有必要的加载
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

贴一下debug的图,这说明,spring是通过类加载器,去找到对应的META-INF/spring.factories,读取里面的内容,并将其,进行注册。自动装配就这么完成了。


截屏2020-07-10下午3.05.31.png 截屏2020-07-10下午3.01.18.png

相关文章

网友评论

      本文标题:spring的自动配置是怎么实现的(一)

      本文链接:https://www.haomeiwen.com/subject/kdgjqktx.html