zl程序教程

您现在的位置是:首页 >  Java

当前栏目

SpringBoot:模块探究之spring-boot-autoconfigure

2023-02-18 16:30:23 时间

顾名思义,Autoconfigure 就是自动配置的意思,SpringBoot 通过 spring-boot-autoconfigure 体现了 “约定优于配置” 这一设计原则!spring-boot-autoconfigure 也是 SpringBoot 最重要的模块之一! SpringBoot 则可以依据 classpath 里面的依赖内容来自动配置 Bean 到 IOC 容器,Auto-configuration 会尝试推断哪些 Beans 是用户可能会需要的。比如如果HSQLDB 包在当前 classpath 下,并且用户并没有配置其他数据库链接,这时候 Auto-configuration 功能会自动注入一个基于内存的数据库连接到应用的 IOC 容器。但是要开启这个自动配置功能需要添加 @EnableAutoConfiguration 注解。 ~ 本篇内容包括:spring-boot-autoconfigure 模块介绍、关于 @EnableAutoConfiguration 注解、spring-boot-autoconfigure 模块总结


文章目录


一、spring-boot-autoconfigure 模块介绍

1、关于 spring-boot-autoconfigure 模块

顾名思义,Autoconfigure 就是自动配置的意思,SpringBoot 通过 spring-boot-autoconfigure 体现了 “约定优于配置” 这一设计原则!spring-boot-autoconfigure 也是 SpringBoot 最重要的模块之一!

SpringBoot 则可以依据 classpath 里面的依赖内容来自动配置 Bean 到 IOC 容器,Auto-configuration 会尝试推断哪些 Beans 是用户可能会需要的。比如如果HSQLDB 包在当前 classpath 下,并且用户并没有配置其他数据库链接,这时候 Auto-configuration 功能会自动注入一个基于内存的数据库连接到应用的 IOC 容器。但是要开启这个自动配置功能需要添加 @EnableAutoConfiguration 注解。

2、spring-boot-actuator 源码地址

spring-boot-autoconfigure 位于 spring-boot 项目中。

spring-boot-autoconfigure 在 源码地址为:https://github.com/spring-projects/spring-boot/tree/v2.1.0.RELEASE/spring-boot-project/spring-boot-autoconfigure


二、关于 @EnableAutoConfiguration 注解

1、@EnableAutoConfiguration 注解

@EnableAutoConfiguration 注解,此注解自动载入应用程序所需的所有Bean,这依赖于 SpringBoot 在类路径中的查找。

# @EnableAutoConfiguration 的源码:

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

通过源码部分可以看到有一特殊的注解——@Import,EnableAutoConfiguration 注解 Import 了一个 AutoConfigurationImportSelector 实例

2、AutoConfigurationImportSelector

AutoConfigurationImportSelector类(implement ImportSelector),实现了 selectImports() 方法,用来筛选被 Import 的 Configuration 类(减去exclude等)

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    //......
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 如果AutoConfiguration没开,返回{}
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        // 将spring-autoconfigure-metadata.properties的键值对配置载入到PropertiesAutoConfigurationMetadata对象中并返回
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        // 基于各种配置计算需要import的configuration和exclusion
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
                annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
             
    // 判断AudoConfiguration是否开启
    protected boolean isEnabled(AnnotationMetadata metadata) {
        if (getClass() == AutoConfigurationImportSelector.class) {
            // 如果配置文件中有"spring.boot.enableautoconfiguration",返回该字段的值;否则返回true
            return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
        }
        return true;
    }
             
    protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
            AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        // 获取注解的属性值
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 从META-INF/spring.factories文件中获取EnableAutoConfiguration所对应的configurations
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 去重,List转Set再转List
        configurations = removeDuplicates(configurations);
        // 从注解的exclude/excludeName属性中获取排除项
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        // 对于不属于AutoConfiguration的exclude报错
        checkExcludedClasses(configurations, exclusions);
        // 从configurations去除exclusions
        configurations.removeAll(exclusions);
        // 由所有AutoConfigurationImportFilter类的实例再进行一次筛选,去
        configurations = filter(configurations, autoConfigurationMetadata);
        // 把AutoConfigurationImportEvent绑定在所有AutoConfigurationImportListener子类实例上
        fireAutoConfigurationImportEvents(configurations, exclusions);
        // 返回(configurations, exclusions)组
        return new AutoConfigurationEntry(configurations, exclusions);
    }
    // ......
}

可见 selectImports() 是 AutoConfigurationImportSelector 的核心函数,其核心功能就是获取 spring.factories 中 EnableAutoConfiguration 所对应的 Configuration 类列表,由 @EnableAutoConfiguration 注解中的 exclude/excludeName 参数筛选一遍,再由 AutoConfigurationImportFilter 类所有实例筛选一遍,得到最终的用于 Import 的 configuration 和 exclusion。

该函数是被谁调用的呢?在 org.springframework.context.annotation.ConfigurationClassParser 类中被 processImports() 调用,而 processImports() 函数被d oProcessConfigurationClass() 调用。

3、@EnableAutoConfiguration 总结

@EnableAutoConfiguration 作用:

  • 从 classpath 中搜索所有 META-INF/spring.factories 配置文件然后,将其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration key 对应的配置项加载到 spring 容器 只有 spring.boot.enableautoconfiguration 为 true(默认为true)的时候,才启用自动配置
  • @EnableAutoConfiguration 还可以进行排除,排除方式有 2 种,一是根据 class 来排除(exclude),二是根据 class name(excludeName)来排除

其内部实现的关键点有:

  1. ImportSelector 该接口的方法的返回值都会被纳入到 spring 容器管理中
  2. SpringFactoriesLoader 该类可以从 classpath 中搜索所有 META-INF/spring.factories 配置文件,并读取配置。

三、spring-boot-autoconfigure 模块总结

SpringBoot 通过 spring-boot-autoconfigure 体现了“约定优于配置”这一设计原则,而 spring-boot-autoconfigure 主要用到了 spring.factories 和几个常用的注解条件来实现自动配置,思路很清晰也很简单。

SpringBoot AutoConfigure 替代了 XML 风格的配置文件,带来了前所未有的体验。spring-boot-autoconfigure 模块基于 SpringFramework 和 SpringBoot 提供的基础设施,构建类配置 Bean+属性文件 配置行为的配置方式,Java 类配置 Bean 为我们提供了更好的编程体验,属性文件配置行为的方式使这种方式拥有跟XML外部配置文件配置方式同样的灵活性。

1、SpringBoot AutoConfigure 对 SpringFramework 和 SpringBoot 的拓展

SpringBoot AutoConfigure 在 SpringFramework 和 SpringBoot 提供的基础设施上做了很多的扩展工作:

  1. 顺序控制:AutoConfigureOrder、AutoConfigureAfter、AutoConfigureBefore;
  2. AutoConfigurationPackage:在 springBoot Mian Class上 标识 @EnableAutoConfiguration 之后,所有子包下面的 Spring 组件都能被扫描到,就是这个注解的能力;
  3. EnableAutoConfiguration/ImportAutoConfiguration:EnableAutoConfiguration 开启自动配置,自动应用 spring.factories 中配置的 AutoConfiguration;ImportAutoConfiguration 跟 EnableAutoConfiguration 相比,只是没有自动配置的功能,给 ImportAutoConfiguration传 入谁的 AutoConfiguration 就应用谁的,单元测试等的场景用到的比较多;
  4. 其他的一些工具类…

2、各种 AutoConfiguration 的实现

所有的 AutoConfiguration 的具体实现包括两部分(主要文件也是这两类,剩下的是一些工具):

  • 一个是标识了 @Configuration 注解的配置类;
  • 另一个是 Property 文件。有些模块比较复杂,像 Security 的 Oauth2 模块

AutoConfiguration 也是 Configuration,被 @Configuration 注解,只不过 spring-boot-autoconfigure 模块内置的 AutoConfiguration 被配置到了 spring.factories 文件中,启动的时候自动配置。