Spring Boot读取自定义配置文件

 更新时间:2021年05月28日 16:05:06   作者:码农小胖哥  
在Spring Boot项目中我们经常需要读取application.yml配置文件的自定义配置,今天就来罗列一下从yaml读取配置文件的一些常用手段和方法。

@Value

首先,会想到使用@Value注解,该注解只能去解析yaml文件中的简单类型,并绑定到对象属性中去。

felord:
  phone: 182******32
  def:
    name: 码农小胖哥
    blog: felord.cn
    we-chat: MSW_623
  dev:
    name: 码农小胖哥
    blog: felord.cn
    we-chat: MSW_623
  type: JUEJIN

对于上面的yaml配置,如果我们使用@Value注解的话,冒号后面直接有值的key才能正确注入对应的值。例如felord.phone我们可以通过@Value获取,但是felord.def不行,因为felord.def后面没有直接的值,它还有下一级选项。另外@Value不支持yaml松散绑定语法,也就是说felord.def.weChat获取不到felord.def.we-chat的值。

@Value是通过使用Spring的SpEL表达式来获取对应的值的:

// 获取 yaml 中 felord.phone的值 并提供默认值 UNKNOWN
@Value("${felord.phone:UNKNOWN}")
 private String phone;

@Value的使用场景是只需要获取配置文件中的某项值的情况下,如果我们需要将一个系列的值进行绑定注入就建议使用复杂对象的形式进行注入了。

@ConfigurationProperties

@ConfigurationProperties注解提供了我们将多个配置选项注入复杂对象的能力。它要求我们指定配置的共同前缀。比如我们要绑定felord.def下的所有配置项:

package cn.felord.yaml.properties;
 
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
 
import static cn.felord.yaml.properties.FelordDefProperties.PREFIX;
 
/**
 * @author felord.cn
 */
@Data
@ConfigurationProperties(PREFIX)
public class FelordDefProperties {
    static final String PREFIX = "felord.def";
    private String name;
    private String blog;
    private String weChat;
}

我们注意到我们可以使用weChat接收we-chat的值,因为这种形式支持从驼峰camel-case到短横分隔命名kebab-case的自动转换。

如果我们使用@ConfigurationProperties的话建议配置类命名后缀为Properties,比如Redis的后缀就是RedisProperties,RabbitMQ的为RabbitProperties。

另外我们如果想进行嵌套的话可以借助于@NestedConfigurationProperty注解实现。也可以借助于内部类。这里用内部类实现将开头yaml中所有的属性进行注入:

package cn.felord.yaml.properties;
 
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
 
import static cn.felord.yaml.properties.FelordProperties.PREFIX;
 
 
/**
 * 内部类和枚举配置.
 *
 * @author felord.cn
 */
@Data
@ConfigurationProperties(PREFIX)
public class FelordProperties {
 
    static final String PREFIX = "felord";
    private Def def;
    private Dev dev;
    private Type type;
 
    @Data
    public static class Def {
        private String name;
        private String blog;
        private String weChat;
    }
 
    @Data
    public static class Dev {
        private String name;
        private String blog;
        private String weChat;
    }
 
    public enum Type {
        JUEJIN,
        SF,
        OSC,
        CSDN
    }
}

单独使用@ConfigurationProperties的话依然无法直接使用配置对象FelordDefProperties,因为它并没有被注册为Spring Bean。我们可以通过两种方式来使得它生效。

显式注入 Spring IoC

你可以使用@Component、@Configuration等注解将FelordDefProperties注入Spring IoC使之生效。

package cn.felord.yaml.properties;
 
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
 
import static cn.felord.yaml.properties.FelordDefProperties.PREFIX;
 
/**
 * 显式注入Spring IoC
 * @author felord.cn
 */
@Data
@Component
@ConfigurationProperties(PREFIX)
public class FelordDefProperties {
    static final String PREFIX = "felord.def";
    private String name;
    private String blog;
    private String weChat;
}

@EnableConfigurationProperties

我们还可以使用注解@EnableConfigurationProperties进行注册,这样就不需要显式声明配置类为Spring Bean了。

package cn.felord.yaml.configuration;
 
import cn.felord.yaml.properties.FelordDevProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
 
/**
 * 使用 {@link EnableConfigurationProperties} 注册 {@link FelordDevProperties}使之生效
 * @author felord.cn
 */
@EnableConfigurationProperties({FelordDevProperties.class})
@Configuration
public class FelordConfiguration {
}

该注解需要显式的注册对应的配置类。

@ConfigurationPropertiesScan

在Spring Boot 2.2.0.RELEASE中提供了一个扫描注解@ConfigurationPropertiesScan。它可以扫描特定包下所有的被@ConfigurationProperties标记的配置类,并将它们进行IoC注入。

package cn.felord.yaml;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 
/**
 * {@link ConfigurationPropertiesScan} 同 {@link EnableConfigurationProperties} 二选一
 *
 * @see cn.felord.yaml.configuration.FelordConfiguration
 * @author felord.cn
 */
@ConfigurationPropertiesScan
@SpringBootApplication
public class SpringBootYamlApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringBootYamlApplication.class, args);
    }
 
}

这非常适合自动注入和批量注入配置类的场景,但是有版本限制,必须在2.2.0及以上。

@PropertySource注解

@PropertySource可以用来加载指定的配置文件,默认它只能加载*.properties文件,不能加载诸如yaml等文件。

@PropertySource相关属性介绍

  • value:指明加载配置文件的路径。
  • ignoreResourceNotFound:指定的配置文件不存在是否报错,默认是false。当设置为 true 时,若该文件不存在,程序不会报错。实际项目开发中,最好设置 ignoreResourceNotFound 为 false。
  • encoding:指定读取属性文件所使用的编码,我们通常使用的是UTF-8。
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Configuration
@PropertySource(value = {"classpath:common.properties"},ignoreResourceNotFound=false,encoding="UTF-8")
@ConfigurationProperties(prefix = "author")
public class Author {
    private String name;
    private String job;
    private String sex;
}

有小伙伴也许发现示例上的@ConfigurationProperties注解了。当我们使用@Value需要注入的值较多时,代码就会显得冗余。我们可以使用@ConfigurationProperties 中的 prefix 用来指明我们配置文件中需要注入信息的前缀

前边提到了用@PropertySource只能加载*.properties文件,但如果我们项目的配置文件不是*.properties这种类型,而是其他类型,诸如yaml,此时我们可以通过实现PropertySourceFactory接口,重写createPropertySource方法,就能实现用@PropertySource也能加载yaml等类型文件。

public class YamlPropertySourceFactory implements PropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String sourceName, EncodedResource resource) throws IOException {
        Properties propertiesFromYaml = loadYaml(resource);
        if(StringUtils.isBlank(sourceName)){
            sourceName =  resource.getResource().getFilename();;
        }

        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }
    private Properties loadYaml(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (IllegalStateException e) {
            // for ignoreResourceNotFound
            Throwable cause = e.getCause();
            if (cause instanceof FileNotFoundException)
                throw (FileNotFoundException) e.getCause();
            throw e;
        }
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Configuration
@PropertySource(factory = YamlPropertySourceFactory.class,value = {"classpath:user.yml"},ignoreResourceNotFound=false,encoding="UTF-8")
@ConfigurationProperties(prefix = "user")
public class User {
    private String username;

    private String password;
}

使用EnvironmentPostProcessor加载自定义配置文件

1、实现EnvironmentPostProcessor接口,重写postProcessEnvironment方法

@Slf4j
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {

        Properties properties = new Properties();

        try {
            properties.load(new InputStreamReader(CustomEnvironmentPostProcessor.class.getClassLoader().getResourceAsStream("custom.properties"),"UTF-8"));

            PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource("custom",properties);
            environment.getPropertySources().addLast(propertiesPropertySource);
        } catch (IOException e) {
          log.error(e.getMessage(),e);
        }

    }
}

2、在META-INF下创建spring.factories

spring.factories文件内容如下:
org.springframework.boot.env.EnvironmentPostProcessor=com.github.lybgeek.env.CustomEnvironmentPostProcessor

1、2步骤实现完后,就可以在代码中直接用@Value的方式获取自定义配置文件内容了

读取的自定义配置文件内容的实现方法有多种多样,除了上面的方法,还可以在以-jar方式启动时,执行形如下命令

java -jar project.jar --spring.config.location=classpath:/config/custom.yml

也能实现。还可以干脆自定义配置文件都以application-*为前缀,比如application-custom,然后在application.properties,使用spring.profiles.include=custom或者spring.profiles.active=custom也可以实现

总结

日常开发中单个属性推荐使用@Value,如果同一组属性为多个则推荐@ConfigurationProperties。需要补充一点的是@ConfigurationProperties还支持使用 JSR303 进行属性校验。好了今天的教程就到这里

相关的demo地址

https://gitee.com/felord/spring-boot-yml.git

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-outside-config

以上就是Spring Boot读取自定义配置文件的详细内容,更多关于Spring Boot读取自定义配置文件的资料请关注脚本之家其它相关文章!

相关文章

  • Java设计模式之建造者模式的示例详解

    Java设计模式之建造者模式的示例详解

    建造者模式,是一种对象构建模式 它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象。本文将通过示例讲解建造者模式,需要的可以参考一下
    2022-10-10
  • 详解Java的Spring框架中的事务管理方式

    详解Java的Spring框架中的事务管理方式

    这篇文章主要介绍了Java的Spring框架中的事务管理方式,Spring框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
    2015-12-12
  • Java 全面掌握网络编程篇

    Java 全面掌握网络编程篇

    网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节
    2021-10-10
  • SpringBoot模板引擎之Thymeleaf的使用

    SpringBoot模板引擎之Thymeleaf的使用

    这篇文章主要介绍了SpringBoot模板引擎之Thymeleaf的使用,模板引擎是以业务逻辑层和表现层分离为目的的,将规定格式的模板代码转换为业务数据的算法实现,它可以是一个过程代码、一个类,甚至是一个类库,需要的朋友可以参考下
    2023-10-10
  • Java日常练习题,每天进步一点点(14)

    Java日常练习题,每天进步一点点(14)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-07-07
  • Java最简单的DES加密算法实现案例

    Java最简单的DES加密算法实现案例

    下面小编就为大家带来一篇Java最简单的DES加密算法实现案例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • 提升性能秘密武器Java Unsafe类面试精讲

    提升性能秘密武器Java Unsafe类面试精讲

    这篇文章主要为大家介绍了提升性能秘密武器Java Unsafe类面试精讲,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Java设计模式中的建造者(Builder)模式解读

    Java设计模式中的建造者(Builder)模式解读

    这篇文章主要介绍了Java设计模式中的建造者(Builder)模式解读, 建造者模式是一种创建对象的设计模式,它通过将对象的构建过程分解为多个步骤,并使用一个建造者类来封装这些步骤,从而使得对象的构建过程更加灵活和可扩展,需要的朋友可以参考下
    2023-10-10
  • 详解基于java的Socket聊天程序——服务端(附demo)

    详解基于java的Socket聊天程序——服务端(附demo)

    这篇文章主要介绍了详解基于java的Socket聊天程序——服务端(附demo),具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-12-12
  • Mybatis List列表In查询实现的注意事项说明

    Mybatis List列表In查询实现的注意事项说明

    这篇文章主要介绍了Mybatis List列表In查询实现的注意事项说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02

最新评论