This post is also available in English and alternative languages. Spring Framework版本:5.1.6.RELEASE (点击跳转官方文档) SpringBoot版本:2.1.4.RELEASE (点击跳转官方文档)
SpringBoot Configuration.
1. 多环境配置 不同的环境配置不同的参数,而且便于部署,减少出错;配置文件的命名规则遵循 application-${profile}.properties
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 spring: profiles: active: dev application: name: springboot-example-01 server: port: 9401 servlet: context-path: /api star: url: www.google.com address: 南京 star: url: www.baidu.com address: 北京
application.yml:默认配置文件。 application-dev.yml:dev 环境的配置文件。 application-prod.yml:prod 环境的配置文件。 在 application.yml
配置文件中,通过设置 spring.profiles.active
来切换选择读取哪个配置文件。
相关测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Data @Configuration @ConfigurationProperties(prefix = "star") public class StarConfigProperty { private String url; private String address; } @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { @Resource StarConfigProperty starConfigProperty; public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } private void process () { log.info("===== starConfigProperty:{}" , starConfigProperty); } }
2. 配置文件细分 上面基于环境,对配置文件进行了区分,dev 环境和 prod 环境的配置内容是不同的;
基于环境,现在继续对配置文件进行拆分,数据库单独一个配置文件,redis单独一个配置文件。配置文件的命名规则遵循 application-${profile}.properties
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 spring: profiles: active: dev include: devRedis,devDatabase application: name: springboot-example-01 server: port: 9401 servlet: context-path: /api star: url: www.google.com address: 南京 star: url: www.baidu.com address: 北京 example: redis: database: 1 host: 127.0 .0 .1 port: 6379 timeout: 5000 example: database: url: jdbc:mysql://localhost/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root passwrod: 123456 example: redis: database: 2 host: 127.0 .0 .2 port: 63792 timeout: 50002 example: database: url: 2jdbc:mysql://localhost/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false username: 2root11 passwrod: 212345611
application.yml:默认配置文件。 application-dev.yml:dev 环境的配置文件。 application-devRedis.yml:dev 环境的 redis 配置。 application-devDatabase.yml:dev 环境的数据配置 application-prod.yml:prod 环境的配置文件。 application-prodRedis:prod 环境的 redis 配置。 application-prodDatabase:prod 环境的数据库配置。 在 application.yml
配置文件中,通过设置spring.profiles.include
来关联各个细分的配置文件。
相关测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Data @Configuration @ConfigurationProperties(prefix = "example.database") public class DataSourceProperty { private String url; private String username; private String passwrod; } @Data @Configuration @ConfigurationProperties(prefix = "example.redis") public class RedisProperty { private Integer database; private String host; private Integer port; private Long timeout; } @Data @Configuration @ConfigurationProperties(prefix = "star") public class StarConfigProperty { private String url; private String address; } @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { @Resource StarConfigProperty starConfigProperty; @Resource DataSourceProperty dataSourceProperty; @Resource RedisProperty redisProperty; public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } private void process () { log.info("starConfigProperty:[{}]" , starConfigProperty); log.info("dataSourceProperty:[{}]" , dataSourceProperty); log.info("redisProperty:[{}]" , redisProperty); } }
3. ConfigurationProperties注解 以下示例,使用 @Configuration
注解实例化 Bean,同时修饰 Bean 为配置类。搭配使用 @ConfigurationProperties
注解使用配置文件中前缀为 star 的值,初始化该 Bean 中同名的属性。
当 Bean 被实例化时,@ConfigurationProperties
会将对应前缀的后面的属性与 Bean 对象的属性匹配,对符合条件则进行赋值。 如果只配置 @ConfigurationProperties
注解不配置 @Configuration
注解,在IOC容器中是获取不到配置文件转化后的 Bean 的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 spring: profiles: active: dev application: name: springboot-example-01 server: port: 9401 servlet: context-path: /api star: url: www.google.com address: 南京 star: url: www.baidu.com address: 北京
3.1. 作用于方法上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Data public class StarConfigProperty { private String url; private String address; } @Configuration public class Model02Config { @ConfigurationProperties(prefix = "star") @Bean(name = "starConfigProperty") public StarConfigProperty createStarConfigProperty () { return new StarConfigProperty (); } } @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { @Resource StarConfigProperty starConfigProperty; public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } private void process () { log.info("===== :{}" , starConfigProperty); } }
3.2. 作用于类上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Data @Configuration @ConfigurationProperties(prefix = "star") public class StarConfigProperty { private String url; private String address; } @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { @Resource StarConfigProperty starConfigProperty; public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } private void process () { log.info("===== starConfigProperty:{}" , starConfigProperty); } }
3.3. 激活ConfigurationProperties注解 可以使用 @Configuration
或 @Component
注解,让 Component Scan 扫描到并加载到 IOC 中,例如 作用于方法上 、作用于类上 两个小节中代码示例,也可以使用 @EnableConfigurationProperties
注解,单独添加到 IOC 容器中。
3.3.1. EnableConfigurationProperties注解 通过配置 @EnableConfigurationProperties
注解,将配置类加载到 IOC 容器中。如果只配置 @ConfigurationProperties
注解,不配置 @EnableConfigurationProperties
注解,在IOC容器中是获取不到配置文件转化的 Bean 的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Data @ConfigurationProperties(prefix = "star") public class StarConfigProperty { private String url; private String address; } @Configuration @EnableConfigurationProperties(StarConfigProperty.class) public class StarConfiguration {} @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { @Resource StarConfigProperty starConfigProperty; public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } private void process () { log.info("starConfigProperty:[{}]" , starConfigProperty); } }
4. 启动时配置校验 配置内容如下:
1 2 3 4 5 6 7 8 test: validation: myName: cyx myBean: name: ccc age: 22
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Data @Validated @Configuration @ConfigurationProperties(prefix = "test.validation") public class ValidationConfiguration { @NotBlank(message = "参数为空") private String myName; @Valid private MyBean myBean; @Data @Accessors(chain = true) public static class MyBean { @NotBlank(message = "name为空") private String name; @NotNull(message = "age为空") private Integer age; @NotBlank(message = "address为空") private String address; } } @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } @Resource ValidationConfiguration validationConfiguration; private void process () { log.info("validationConfiguration:[{}]" , validationConfiguration); } }
通过在字段上添加 validation 相关注解,同时在类上添加 @Validated
注解,就可以在配置参数传入到应用中时进行有效的校验。
测试结果如下:
1 2 3 4 5 6 7 8 Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'test.validation' to com.yxcheng.configuration.module08.ValidationConfiguration$ $ EnhancerBySpringCGLIB$ $ 23b5265b failed: Property: test.validation.myBean.address Value: null Reason: address为空 Action: Update your application's configuration
5. 复杂类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 spring: profiles: active: dev application: name: springboot-example-01 server: port: 9401 servlet: context-path: /api star: url: www.google.com address: 南京 historyProperties: version: 5 pathOrUrl: C\:/Library/maven_repository dataDirName: data1 kind: LOCAL lastUpdate: 1604987319723 id: local locations: 中山陵,新街口,河西中央公园 relations: aaa: - $.services[key='dev111'].configs.providers.dialects.voices.voice[code='%s'] bbb: - $.services[key='dev111'].configs.settings.disabasdledSasdkills.skill[code='%s'] - $.services[key='dev111'].configs.settings.alwasddysMaatchStatementSkills[code='%s'] - $.services[key='dev111'].configs.providers.includedSkills.staasdndardfasSkfsaill[code='%s'] - $.services[key='dev111'].configs.skill[code='%s'] star: url: www.baidu.com address: 北京 historyProperties: version: 6 pathOrUrl: C\:/Library/maven_repository dataDirName: data2 kind: LOCAL2 lastUpdate: 1604987319723 -2 id: local-2 locations: 天安门,天坛,人民大会堂,国家博物馆 relations: aaa: - $.services[key='dev222'].configs.providers.dialects.voices.voice[code='%s'] bbb: - $.services[key='dev222'].configs.settings.disabasdledSasdkills.skill[code='%s'] - $.services[key='dev222'].configs.settings.alwasddysMaatchStatementSkills[code='%s'] - $.services[key='dev222'].configs.providers.includedSkills.staasdndardfasSkfsaill[code='%s'] - $.services[key='dev222'].configs.skill[code='%s']
相关测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Data @Configuration @ConfigurationProperties(prefix = "star") public class StarConfigProperty { private String url; private String address; private Map<String, String> historyProperties = new HashMap <>(); private List<String> locations = new ArrayList <>(); private Map<String, List<String>> relations; } @Slf4j @SpringBootApplication public class ApplicationSpringBootExample01 { @Resource StarConfigProperty starConfigProperty; public static void main (String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args); ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class); applicationContextBean.process(); } private void process () { log.info("starConfigProperty:[{}]" , starConfigProperty); } }
AutoConfigureBefore、AutoConfigureAfter、AutoConfigureOrder 三个注解的使用。
先说结论:这三个注解 在自动配置中使用,即:封装自定义 starter 中使用 ,而不是在业务工程中的@Configuration
配置类里使用,那会毫无效果 。
You can use the @AutoConfigureAfter or @AutoConfigureBefore annotations if your configuration needs to be applied in a specific order. For example, if you provide web-specific configuration, your class may need to be applied after WebMvcAutoConfiguration.
If you want to order certain auto-configurations that should not have any direct knowledge of each other, you can also use @AutoConfigureOrder. That annotation has the same semantic as the regular @Order annotation but provides a dedicated order for auto-configuration classes.
49.2 Locating Auto-configuration Candidates
6.1. 使用 先添加一个普通配置类,这个类放在 springboot 主类可以扫描到的包中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Data @Slf4j @Configuration @ConfigurationProperties(prefix = "star") public class StarConfig { public StarConfig () { log.info("我是被自动扫描的配置类 star,初始化啦...." ); } private String url; private String address; private Map<String, String> historyProperties = new HashMap <>(); private List<String> locations = new ArrayList <>(); private Map<String, List<String>> relations; }
下面这两个类用来模拟需要先后加载的配置类,注意:这两个配置类需要放在 springboot 主类扫描不到的包中!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Data @Slf4j @Configuration @AutoConfigureBefore(DataBaseConfig.class) @ConfigurationProperties(prefix = "example.redis") public class RedisConfig { RedisConfig() { log.info("配置类 redis 构造器被执行..." ); } private Integer database; private String host; private Integer port; private Long timeout; } @Data @Slf4j @Configuration @ConfigurationProperties(prefix = "example.database") public class DataBaseConfig { DataBaseConfig() { log.info("配置类 database 构造器被执行..." ); } private String url; private String username; private String passwrod; }
然后在 resource/META-INF/spring.factories
文件中添加这两个类的路径:
1 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ external.DataBaseConfig,external.RedisConfig
运行看结果:
1 2 3 我是被自动扫描的配置类 star,初始化啦.... 配置类 redis 构造器被执行... 配置类 database 构造器被执行...
RedisConfig 先于 DataBaseConfig 被加载。
模拟测试需要注意:
要把 RedisConfig 和 DataBaseConfig 这两个类挪动到 SpringBootApplication(主类) 扫描不到的包内,切记:一定且必须是扫描不到的包内 当前工程中 resources/META-INF/spring.factories
文件中内容的前后顺序对结果无影响。 StarConfig 配置类会被优先加载,SpringBoot 的自动配置均是通过 resources/META-INF/spring.factories
文件来指定的,它的优先级最低(执行时机是最晚的);基于 SpringBootApplication(主类) 下自动扫描进来的类优先级是最高的。
7. 关于bootstrap.yml SpringBoot 项目中如果没有依赖 spring-cloud-context
的话,是不会读取 bootstrap.yml 文件
bootstrap.yml 配置是 SpringCloud 项目才会用到的,如果项目仅仅是一个 SpringBoot 项目,只会识别 application.yml 配置文件。
由于 SpringCloud 是基于 SpringBoot 构建的,所有 SpringCloud 项目两种文件都会识别,这个时候才有优先级的说法,SpringCloud 项目是会优先读取 bootstrap.yml 配置,再读取 application.yml 配置。
8. 依赖POM 以上示例的依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-actuator</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-validation</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-freemarker</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-logging</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-aop</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > <exclusions > <exclusion > <groupId > org.junit.vintage</groupId > <artifactId > junit-vintage-engine</artifactId > </exclusion > </exclusions > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-devtools</artifactId > <optional > true</optional > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-configuration-processor</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.22</version > </dependency > </dependencies >
9. Reference