SpringBoot自动配置原理

SpringBoot项目无需各种配置文件,一个main方法,就能把项目启动起来。那么我们看看SpringBoot是如何进行自动配置和启动的。

先看下图的SpringBoot项目的启动类

SpringBoot程序能够实现自动配置主要来源于@SpringBootApplication这个复合注解,其中有三个注解是比较重要的:

1.@ComponentScan注解(扫描注解)

   这个注解在Spring中很重要,它对应XML配置中的元素

   作用:自动扫描包(扫描当前主启动类同级的包)并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中。

2.@SpringBootConfiguration注解

   表明这是一个SpringBoot配置类,配置类就是对应Spring的xml配置文件

3.@EnableAutoConfiguration注解

   开启自动配置功能,里面包含两个比较重要的注解@AutoConfigurationPackage和@Import。

 

@AutoConfigurationPackage:自动配置包

@Import : ( 自动注册包和@ComponentScan自动扫描包,是联动的)Spring底层注解@Import,给容器中导入一个组件。

Registrar.class 作用:将主启动类所在包及包下面所有子包里面的所有组件扫描到Spring容器

@Import(AutoConfigurationImportSelector.class): 给容器导入组件

此注解是自动装配的核心注解,其导入的AutoConfigurationImportSelector类中有个selectImports( )方法, 此方法中有一个 getAutoConfigurationEntry( )方法用于获取自动配置的实体,

getAutoConfigurationEntry( )方法中有一个 this.getCandidateConfigurations(annotationMetadata, attributes) 获得候选配置的方法

getCandidateConfigurations()这个方法又调用SpringFactoriesLoader 类的静态方法!

我们进入SpringFactoriesLoader类loadFactoryNames() 方法------->获取所有的加载配置。

在这里插入图片描述

然后继续点击查看 loadSpringFactories 方法

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

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

loadSpringFactories 方法中的classLoader.getResources(“META-INF/spring.factories”) —》获取项目资源;

spring-boot-autoconfigure jar 包下就有这样一个spring.factories文件。打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔,而\表示忽略换行

 

可以看出 spring.factories 文件可以将项目包以外的 bean(即在 pom 文件中添加依赖中的 bean)注册到 spring 容器。由于@ComponentScan 注解只能扫描项目包内的 bean并注册到spring容器中,因此需要 @EnableAutoConfiguration 注解来注册项目包外的bean。而 spring.factories 文件,则是用来记录项目包外需要注册的bean类名。

思考:这么多自动配置为什么有的没有生效,需要导入对应的start才能有作用!

posted @ 2021-05-21 13:47  江南大才子  阅读(487)  评论(0编辑  收藏  举报