[Spring Boot] 配置文件加载[超详细]

[Spring Boot] 配置文件加载[超详细]

手机用户请 横屏获取最佳阅读体验, REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。

平台

地址

CSDN

https://blog.csdn.net/sinat_28690417

简书

https://www.jianshu.com/u/3032cc862300

个人博客

https://yiyuery.club

分享整理 Spring Boot 下的配置文件加载

DEV-ENV

Spring Boot: 2.1.0
JDK: 1.8

主要分成以下几个方面来介绍下使用和配置方式:

  • 项目内配置文件加载方式
  • 项目外的配置文件
  • 复杂参数读取
  • yaml文件读取
  • Environment配置加载分析

常见配置加载方式

  • 项目内加载
  • 项目外加载
  • 复杂参数加载

项目内加载

1、 @Value 方式加载 application.yaml 中配置

application.yaml 中配置项

props:
  db-name: db_capsule

测试

@Value("${props.db-name}")
private String dbName;

@Test
public void testX1(){
    System.out.println(dbName);
}

2、 @PropertySource(value="classpath:props.properties")方式

props.properties 中配置项

a.b=1
@Configuration
@PropertySource("classpath:conf/props.properties")
public class PropertiesLoader {

    @Value("${a.b}")
    private Integer ab;

    @Bean
    public Integer ab(){
        return ab;
    }
}

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CommonBootSupportApplicationTest {

    @Resource(name="ab")
    private Integer ab;

    @Test
    public void testX1(){
        System.out.println(ab);
    }
}

项目外加载

1、 配置 PropertyPlaceholderConfigurer

在项目外指定目录下新增一个properties文件

@Configuration
public class ResourceLoader {

    @Bean
    public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer(){
        PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
        configurer.setLocation(new FileSystemResource(Paths.get("/Users/xiazhaoyang/Documents/capsule/architectrue-adventure/conf/props.properties")));
        //此处亦可添加项目路径下资源,使用ClassPathResource即可
        return configurer;
    }
}

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CommonBootSupportApplicationTest {

    @Resource(name="ab")
    private Integer ab;
    @Value("${a.b.c}")
    private Integer abc;

    @Test
    public void testX1(){
        System.out.println(ab);
        System.out.println(abc);
    }
}

复杂参数加载

1、 实例对象成员属性自动注入

person:
  auto:
    name: x1
    age: 18
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "person.auto")
public class PersonAutoConfig {

    private String name;

    private Integer age;
}

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CommonBootSupportApplicationTest {

    @Resource
    private PersonAutoConfig personAutoConfig;

    @Test
    public void testX1(){
        //...
        System.out.println(personAutoConfig.toString());
        //...
    }
}

2、 实例集合属性自动注入

person:
  auto:
    name: x1
    age: 18
  list:
    personList:
      - name: x2
        age: 19
      - name: x3
        age: 20
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "person.list")
public class PersonListAutoConfig {

    private List<PersonAutoConfig> personList;
}

测试

@Resource
private PersonListAutoConfig personListAutoConfig;

@Test
public void testX1(){
    System.out.println(personListAutoConfig);
}

自定义 YAML 文件读取

@Bean
@Primary
public CapPropertyPlaceholderConfigurer propertyConfigurer() throws IOException {
    CapPropertyPlaceholderConfigurer configurer = new CapPropertyPlaceholderConfigurer();
    YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
    //加载本地外部配置的yaml,也可以选择项目内
    yaml.setResources(new FileSystemResource(Paths.get(RunnerMonitor.getEnvConfPath().getConfPath(), "config.yaml").toFile()));
    Properties props = new Properties();
    props.putAll(Objects.requireNonNull(yaml.getObject()));
    //项目内 properties 配置文件加载
    props.load(PropertiesLoaderSupport.class.getResourceAsStream("/constants.properties"));
    configurer.setProperties(props);
    configurer.setFileEncoding(BasicConstants.DEFAULT_ENCODING);
    return configurer;
}

CapPropertyPlaceholderConfigurer

public class CapPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{

    private Properties capProps;

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
        capProps = props;
    }

    /**
     * 自定义配置获取,对外提供入口
     * @return
     */
    public Properties getCapProps() {
        return capProps;
    }
}

此处主要实现本地和外部配置文件加载的功能,并提供出口,在其他地方注入实例 CapPropertyPlaceholderConfigurer即可获取到对应自定义的配置属性信息

Environment配置加载分析

今天在做一个功能开发的时候,发现加载的配置,在 Environment实例中一直获取不到对应的配置属性,为此特地做个测试。

首先,外部 props文件展示下,方便比对

x.a.b=1
x.a.b.c=2

所以内外配置项各不相同,然后内部原有的配置变量 a.b=123删除掉,在外部 props中增加 a.b=321的配置,接下来我们 测试下输出

@Value("${a.b.c}")
private Integer abc;
@Value("${x.a.b.c}")
private Integer xabc;
@Value("${x.a.b}")
private Integer xab;
@Resource
private Environment environment;

@Test
public void testX1(){
    System.out.println(abc);
    System.out.println(xab);
    System.out.println(xabc);
    System.out.println(environment.getProperty("a.b"));
    System.out.println(environment.getProperty("x.a.b"));
    System.out.println(environment.getProperty("x.a.b.c"));
}

通过输出可以看出通过 PropertyPlaceholderConfigurer或其子类加载的配置,是不会写入到 Environment实例的。

此处需要 注意,由于配置了 PropertyPlaceholderConfigurer,需要注意在加载配置的时候,需要设置 ignore-unresolvable为true,不然会报 a.b无法通过${a,b}解析获取的错误

@Bean
public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer(){
    PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
    configurer.setIgnoreUnresolvablePlaceholders(true);
    configurer.setLocation(new FileSystemResource(Paths.get("/Users/xiazhaoyang/Documents/capsule/architectrue-adventure/conf/props.properties")));
    return configurer;
}
2019-07-28 19:00:54.801  INFO 72049 --- [           main] e.c.b.s.CommonBootSupportApplicationTest : Started CommonBootSupportApplicationTest in 4.303 seconds (JVM running for 6.642)
321
1
2
null
null
null

那么,如果项目外定义的变量和项目内重复又会怎么样呢?我们在项目内 props配置文件中还原 a.b=123配置属性,测试下输出

321
1
2
123
null
null

显然, Environment 实例获取到的是项目内的配置项,和外部配置文件加载互不干扰。

所以该小节结论是外部通过 PropertyPlaceholderConfigurer注入的参数配置不会影响到 Environment获取的配置数据,如果想用自身配置项的话,需要自定义处理类,比如继承指定接口,或是通过配置项,将项目依赖的 Environment获取配置项的方式转换到自身配置类。

总结

好了,中心思想来了哦。总结下今天的整理,首先,我们了解了Spring Boot 中配置 文件的几种加载方式。然后呢?1、通过 @Value在注入类的实例中直接定义变量从 applicaition.yaml中获取 2、通过注解 @Configuration@PropertySource("classpath:conf/props.properties") 获取项目内其他路径的配置文件 3、怎么给注入的实例自动填充配置参数(集合和对象中的普通参数) 4、yaml配置文件的加载 5、外部配置文件的加载方式 6、外部配置文件加载和 Environment获取配置参数的方式是互不干扰的,如果需要改写某个类的实现,原来依赖于 Environment,但是需要调整为自定义的外部配置的话,需要自定义实现,比方说 jasypt的加密密钥,原生的方法使用的是项目内的配置文件,且是通过 Environment获取的。但是对于密钥这种敏感信息,我们一般是不放在项目代码中的,安全性需要保证,就需要自定义配置参数和加载路径。7、最后特别注意下如果配置了 PropertyPlaceholderConfigurer时最好是开启 configurer.setIgnoreUnresolvablePlaceholders(true);,不然遇到解析不到的属性就会报错。

REFRENCES

  • 解决 IllegalArgumentException: Could not resolve placeholder in string value "${XXXXXX}"
  • spring boot 自定义配置属性的各种方式

原文发布于微信公众号 - 架构探险之道(zacsnz1314)

原文发表时间:2019-07-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券