Environment

spring 的环境配置,从上层 Environment 接口抽象出了 profile 和 property
针对 Property,又抽象出各种 PropertySource 类代表配置源。一个环境下可能有多个配置源,每个配置源中有诸多配置项。在查询配置信息时,需要按照配置源优先级进行查询。
Profile 定义了场景的概念。通常,我们会定义类似 dev、test、stage 和 prod 等环境作为不同的Profile,用于按照场景对 Bean 进行逻辑归属。同时,Profile 和配置文件也有关系,每个环境都有独立的配置文件,但我们只会激活某一个环境来生效特定环境的配置文件。
property 和 profile 的关系如下:

image.png

demo,通过 standardEnvironment,查看 spring 所有的 propertySource 配置

  1. @Component
  2. @Slf4j
  3. public class LocalEnvironment {
  4. @Autowired
  5. private StandardEnvironment env;
  6. @PostConstruct
  7. public void init() {
  8. Arrays.asList("server.port", "spring.application.name", "customized.demon.name").forEach(
  9. k -> {env.getPropertySources().forEach(p -> {
  10. if (p.containsProperty(k)) {
  11. log.info("LocalEnvironment propertySource:{},value:{}", p, p.getProperty(k));
  12. }
  13. });
  14. });
  15. log.info("@----");
  16. Iterator<PropertySource<?>> iterator = env.getPropertySources().iterator();
  17. while (iterator.hasNext()) {
  18. System.out.println(iterator.next());
  19. }
  20. }
  21. }

打印结果:

  1. 2021-11-21 18:18:06.539 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : LocalEnvironment propertySource:ConfigurationPropertySourcesPropertySource {name='configurationProperties'},value:8888
  2. 2021-11-21 18:18:06.541 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : LocalEnvironment propertySource:OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/bootstrap.yml]'},value:8888
  3. 2021-11-21 18:18:06.541 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : LocalEnvironment propertySource:ConfigurationPropertySourcesPropertySource {name='configurationProperties'},value:springboot-mybatis
  4. 2021-11-21 18:18:06.541 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : LocalEnvironment propertySource:OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/bootstrap.yml]'},value:springboot-mybatis
  5. 2021-11-21 18:18:06.541 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : LocalEnvironment propertySource:ConfigurationPropertySourcesPropertySource {name='configurationProperties'},value:micahel
  6. 2021-11-21 18:18:06.541 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : LocalEnvironment propertySource:OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/bootstrap.yml]'},value:micahel
  7. 2021-11-21 18:18:06.541 INFO 5333 --- [ main] c.a.d.m.environment.LocalEnvironment : @ == ==
  8. ConfigurationPropertySourcesPropertySource {name='configurationProperties'}
  9. StubPropertySource {name='servletConfigInitParams'}
  10. ServletContextPropertySource {name='servletContextInitParams'}
  11. MapPropertySource {name='systemProperties'}
  12. OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}
  13. RandomValuePropertySource {name='random'}
  14. MapPropertySource {name='springCloudClientHostInfo'}
  15. OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/bootstrap.yml]'}
  16. MapPropertySource {name='defaultProperties'}

如果需要获取spring 的某一个配置,直接注入 Envrironment 接口,调用它的 getProperty()方法即可;
�spring 配置的优先级, 版本 2.6.1:链接
Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use a variety of external configuration sources, include Java properties files, YAML files, environment variables, and command-line arguments.
Property values can be injected directly into your beans by using the @Value annotation, accessed through Spring’s Environment abstraction, or be bound to structured objects through @ConfigurationProperties.
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order (with values from lower items overriding earlier ones):

  1. Default properties (specified by setting SpringApplication.setDefaultProperties).
  2. @PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging. and spring.main. which are read before refresh begins.
  3. Config data (such as application.properties files).
  4. A RandomValuePropertySource that has properties only in random.*.
  5. OS environment variables.
  6. Java System properties (System.getProperties()).
  7. JNDI attributes from java:comp/env.
  8. ServletContext init parameters.
  9. ServletConfig init parameters.
  10. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
  11. Command line arguments.
  12. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.
  13. @TestPropertySource annotations on your tests.
  14. Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.

Config data files are considered in the following order:

  1. Application properties packaged inside your jar (application.properties and YAML variants).
  2. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
  3. Application properties outside of your packaged jar (application.properties and YAML variants).
  4. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).

ConfigurationProperties +EnableConfigurationProperties

配置文件如何注入到 spring 容器?

使用注解 @ConfigurationProperties ,@NestedConfigurationProperty ,配合注解
@EnableConfigurationProperties 可以映射配置文件的配置到 spring 容器中的 java 对象。栗子:

  1. @ConfigurationProperties(prefix = "magic-api")
  2. public class MagicAPIProperties {
  3. private String prefix;
  4. @NestedConfigurationProperty
  5. private ResourceConfig resource = new ResourceConfig();
  6. }
  1. public class ResourceConfig {
  2. /**
  3. * 存储类型,默认是文件
  4. */
  5. private String type = "file";
  6. /**
  7. * 文件存储位置
  8. */
  9. private String location = "/data/magic-api/";
  10. /**
  11. * 是否是只读模式
  12. */
  13. private boolean readonly = false;
  14. /**
  15. * 前缀
  16. */
  17. private String prefix = "magic-api";
  18. /**
  19. * 使用数据库存储时的表名
  20. */
  21. private String tableName = "magic_api_file";
  22. /**
  23. * 使用数据库存储时使用的数据源
  24. */
  25. private String datasource;
  26. // 省略 set get
  27. }
  1. @Configuration
  2. @EnableConfigurationProperties(MagicAPIProperties.class)
  3. public class MagicAPIAutoConfiguration {
  4. private final MagicAPIProperties properties;
  5. public MagicAPIAutoConfiguration(MagicAPIProperties properties){
  6. this.properties = properties;
  7. }
  8. @Bean
  9. @ConditionalOnMissingBean
  10. @ConditionalOnProperty(prefix = "magic-api", name = "resource.type", havingValue = "redis")
  11. public Resource magicRedisResource(RedisConnectionFactory connectionFactory) {
  12. ResourceConfig resource = properties.getResource();
  13. return new RedisResource(new StringRedisTemplate(connectionFactory), resource.getPrefix(), resource.isReadonly());
  14. }
  15. }

ConfigurationProperties +configuration

  1. @ConfigurationProperties("e6.tms.customer.blx")
  2. @Configuration
  3. @Data
  4. public class BlxCommonProperties {
  5. private Integer corpId;
  6. private List<Integer> processEventCorpIds;
  7. }

配置文件这样写,就可以把数据注入到数组中。通过 @auwired 这个类 BlxCommonProperties ,就可以直接使用

  1. e6.tms.customer.blx.processEventCorpIds[0] = 193729
  2. e6.tms.customer.blx.processEventCorpIds[1] = 210364

propertySource

  1. @Configuration
  2. @PropertySource("classpath:/com/myco/app.properties")
  3. public class AppConfig {
  4. @Autowired
  5. Environment env;
  6. @Bean
  7. public TestBean testBean() {
  8. TestBean testBean = new TestBean();
  9. testBean.setName(env.getProperty("testbean.name"));
  10. return testBean;
  11. }
  12. }

这样可以将 class路径下 app.properties 里面的键值对注入到 spring environment。链接