SpringBoot 自动配置


SpringBoot 配置文件

配置文件

  1. SpringBoot 使用全局配置文件,配置文件名称固定。
  • application.perperties
  • application.yml
  1. 配置文件生效的本质,Springboot 底层的自动配置实现,可以修改底层配置的默认值。

3、配置文件加载位置。

  • file:/config/ file 是指:项目文件根路径。
  • file:./
  • classpath:/config/
  • classpath:/

说明:以上配置按照优先级顺序从高到底,所有位置的文件都会被加载到,高优先级会覆盖低优先级的配置内容。可以通过修改 spring.config.location来改变默认配置。彼此的配置会互补并集

设置配置文件信息

  • 支持.properties yml 两种文件格式,全局配置文件名称固定 application
  • 支持的数据格式 key = value ,value 属性可以设置多种数据类型。
    • 常见基本数据类型。int、String等
    • list、map 等

获取配置信息

  • @Value("filed"),spring 提供的获取环境变量或配置文件中的值。
  • @configurationProperties(prefi=xxx.xxx),SpringBoot 提供的注解,作用在类中,可以指定前缀为映射,获取配置文件中的信息和类属性映射。支持批量一次映射所有的属性,支持松散绑定(驼峰,下划线切分)。
  • 配置文件路径设置,默认从classPath/lresource/application.properties下获取文件,我们可以在指定文件地址。
    • 一、PropertySource("Path"),设置配置文件指定地址。
    • 二、importSource("Path"),读取指定路径下配置文件。

容器中添加组件

  • @configuration 注解:SpringBoot 推荐使用的,添加组件方式。作用在类上,指明当前类是一个配置类。
  • @bean 注解:作用在方法中,可以把方法返回的对象添加到容器中,添加到容器中实例 ID 名称 为方法的名称。

配置文件占位符

  • RandomValuePropertySource : 配置文件可以使用随机数。例如:${random.value}、${random.int(10)}、${random.uuid}
  • 属性配置文件占位符。
    • 可以在配置文件中引用前面配置过的属性(优先级前配置过的都可以在这里使用)。
    • ${app.name:默认值}来指定找不到属性时的默认值。

Profile 多环境配置文件

Profile 是 Spring 对不同环境提供不同配置功能的支持,可以通过激活、设置参数做到环境切换,成见使用场景 测试环境、灰度环境、线上环境。
SpringBoot 启动会默认扫描 application.properties文件或者 applcation.yml 文件,做为SpringBoot的默认配置文件。
  • 多 Profile 文件形式:
    格式说明:properties.{profile}.properties。例如:properties.dev.properties等
  • yml 格式配置还支持多文档块配置。
    方法:--- 分割配置
  • 激活方式:
    • 命令行:--spring.profiles.active=dev
    • 主配置文件: spring.profile.active=dev
    • JVM 启动参数: -Dspring.profile.active=dev

外部配置加载顺序

SpringBoot 会从下列位置获取配置,优先级从高到底,相处互补配置。

  • 命令行参数,--配置项=参数值 多个用空格隔开。
  • 来自 java:comp/env 的 JNDI 属性
  • Java 系统属性 System.getProperties()
  • 操作系统环境变量
  • RandomValuePropertySource 配置的 random.* 属性
  • jar 外部的配置文件
  • jar 包内部的配置文件
  • @configuration 注解上的 @PropertySource
  • 通过SpringApplication.setDefalultProperties 指定的默认属性值。

自动配置原理

自动配置原理

  1. SpringBoot 启动的时候加载配置类,开启自动配置功能 @EnableAutoConfiguration。

    @EnableAutoConfiguration 类上的注解 @Import(AutoConfigurationImportSelector.class)

    总结:将类路径下 META-INF//spring.factories 加载到 IOC 容器,从而做到自动配置功能。

点击查看代码
```AutoConfigurationImportSelector ```注解类中
// 选择要自动配置的生效信息

public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

// 获取要自动配置项
```protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 加载配置条件信息
    List configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

// 根据条件加载

protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List 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;
}

// 加载配置名称

public static List loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
 	ClassLoader classLoaderToUse = classLoader;
 	if (classLoaderToUse == null) {
 		classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
 	}
 	String factoryTypeName = factoryType.getName();
 	return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

// 加载配置工厂

private static Map> loadSpringFactories(ClassLoader classLoader) {
    Map> result = cache.get(classLoader);
    if (result != null) {
        return result;
    }

    result = new HashMap<>();
    try {
        // 类加载器加载配置文件路径地址,会加载所有 jar META-INF 文件下,Spring.factory 文件。
        // 扫描文件包装成 properties 对象,交给容器
        // FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                String factoryTypeName = ((String) entry.getKey()).trim();
                String[] factoryImplementationNames =
                    StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
                for (String factoryImplementationName : factoryImplementationNames) {
                    result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                        .add(factoryImplementationName.trim());
                }
            }
        }

        // Replace all lists with unmodifiable lists containing unique elements
        result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
                          .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
        cache.put(classLoader, result);
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                                           FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
    return result;
}