往期文章回顾:
前言 上弹说到如何使用Spring Boot问候一下世界,想必大家都对Spring Boot已经有一定的掌握了。如果还没看的,没关系,可以点击上面往期回顾链接前去学习。
今天我们一起来学习Spring Boot第二弹,玩转Spring Boot配置文件。
说起Spring Boot的配置文件,真的是爱恨交加,相对于之前Spring大量的配置文件,现在的Spring Boot简直简直简直。。。,怎一个爽字了得。当然了,爽的同时,也迎来了不少困扰,比如:我们对于Spring Boot是如何实现的只需要修改配置文件就能达到一定效果也是充满了好奇,这个就需要我们去阅读Spring Boot的源码-自动装配原理了,。这里我就不再赘述了,后面我会出专门针对源码进行分析的文章,敬请期待吧!!!
话不多说,开搞!!!
Spring Boot配置文件格式Spring Boot 官方提供了两种常用的配置文件格式,分别是properties、YML格式。相比于properties来说,YML更加年轻,层级也是更加分明。强烈推荐使用YML格式
Spring Boot配置文件优先级加载机制Spring Boot项目启动会扫描以下位置的application.properties或者application.yml作为默认的配置文件.
- file:./config/
- file:./config,file:./config/";
private static final String DEFAULT_NAMES = "application";
private static final Set
NO_SEARCH_NAMES = Collections.singleton((Object)null); private static final Bindable STRING_ARRAY = Bindable.of(String[].class); private static final Bindable - > STRING_LIST = Bindable.listOf(String.class);
private static final Set
- 注入属性支持批量,仅仅指定一个前缀prefix即可
- 数据类型支持复杂数据,比如List、Map
- 属性名匹配规则-松散绑定,比如a-b,a_b,aB,A_B都可以取值
- 支持JAVA的JSR303数据校验
- 使用spring.profiles.active激活
- 打成jar包运行时候使用命令行激活
- 使用虚拟机参数激活
- 在java代码中激活
LOAD_FILTERED_PROPERTY; public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active"; public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include"; public static final String CONFIG_NAME_PROPERTY = "spring.config.name"; public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location"; public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location"; ... ... ... } 然后在ConfigFileApplicationListener类中的getSearchLocations方法中去逗号解析成Set,其中内部类Loader负责这一配置文件的加载过程,包括加载profile指定环境的配置,以application+’-’+name格式的拼接加载。
内部类Loader的load方法
private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.documentFilterFactory filterFactory, ConfigFileApplicationListener.documentConsumer consumer) { this.getSearchLocations().forEach((location) -> { String nonOptionalLocation = ConfigDataLocation.of(location).getValue(); boolean isDirectory = location.endsWith("/"); Setnames = isDirectory ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES; names.forEach((name) -> { this.load(nonOptionalLocation, name, profile, filterFactory, consumer); }); }); } getSearchLocations()方法
private SetgetSearchLocations() { Set locations = this.getSearchLocations("spring.config.additional-location"); if (this.environment.containsProperty("spring.config.location")) { locations.addAll(this.getSearchLocations("spring.config.location")); } else { locations.addAll(this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, "classpath:/,classpath:/config/,file:./,file:./config @ConfigurationProperties(prefix = "person") @Bean public Person person(){ return new Person(); } 综上所述
@ConfigurationProperties注解能够轻松的让配置文件跟实体类绑定在一起。具有以下优点:
值得关注的是:@ConfigurationProperties这个注解仅仅是支持从Spring Boot的默认配置文件中取值,也就是application.properties、application.yml、application.yaml,那我们如何从自定义配置文件取值呢???
别着急,有解决办法,那就是再加一个注解:@PropertySource(value = "classpath:custom-profile.properties"),下面会有对@PropertySource注解的介绍。请耐心往下面看。
自定义配置文件并取值@Value
@Value这个注解我们应该都比较熟悉了,Spring中从属性取值的注解,支持SPEL表达式,不支持复杂的数据类型,比如Map、List。使用可以参考上面实体类里面的代码。Spring Boot在启动的时候会自动加载application.xxx,但是有的时候为了避免application.xxx配置文件过于臃肿,就需要我们自定义配置文件,那么自定义配置文件的话,我们如何从自定义配置文件里面取值呢?这时候就需要配合@PropertySource这个注解使用了。
使用@PropertySource注解
在配置类上标注@PropertySource并指定你自定义的配置文件即可。可以参考下面代码
@Data @AllArgsConstructor @NoArgsConstructor @Slf4j @Component @PropertySource(value = {"classpath:config/custom-profile.properties"}, encoding = "utf-8") @ConfigurationProperties(prefix = "person") public class Person { @Value("${person.name}") private String name; @Value("${person.age}") private int age; @Value("${person.birthday}") private Date birthday; private Listhobby; private Map assets; private Dog dog; } 对应配置文件
person.name=tinygrey person.age=18 person.birthday=2020/11/23 person.hobby[0]=打篮球 person.hobby[1]=睡觉 person.hobby[2]=玩游戏 person.hobby[3]=学习 person.assets.phone=iphone 12 person.assets.car=捷豹 person.dog.name=奶狗 person.dog.age=3@PropertySource注解属性
value:是一个数组,可以指定多个配置文件同时引入。
value是数组那么问题就来了:如果同时加载多个配置文件,并且不同配置文件中对同一个属性设置了不同的值,那么Spring会识别哪一个呢?创建两个配置文件custom-profile.yml、custom-profile1.yml,如下去引入。
@PropertySource(value = {"classpath:config/custom-profile.yml","classpath:config/custom-profile1.yml"}) public class Person { ... }我们可以通过控制变量法进行测试,具体过程我这里就不赘述了。
直接说结论吧:Spring加载顺序为从左到右顺序加载,后加载的会覆盖先加载的属性值。另外需要注意的是:@PropertySource默认加载xxx.properties类型的配置文件,不能加载YML格式的配置文件。如何解决呢?下面来解决这一问题
加载自定义YML格式的配置文件@PropertySource注解有一个属性factory,默认值是PropertySourceFactory.class,这个就是用来加载properties格式的配置文件,那我们自定义一个用来加载YML格式的配置文件不就可以了嘛?上代码
public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { @Override public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException { String sourceName = name != null ? name : resource.getResource().getFilename(); if (!resource.getResource().exists()) { assert sourceName != null; return new PropertiesPropertySource(sourceName, new Properties()); } else if (Objects.requireNonNull(sourceName).endsWith(".yml") || sourceName.endsWith(".yaml")) { Properties propertiesFromYaml = loadYamlProperties(resource); return new PropertiesPropertySource(sourceName, propertiesFromYaml); } else { return super.createPropertySource(name, resource); } } private Properties loadYamlProperties(EncodedResource resource){ YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); factory.setResources(resource.getResource()); factory.afterPropertiesSet(); return factory.getObject(); } }我们写好上面的代码之后,只需要添加@PropertySource注解中factory属性指定为YmlPropertySourceFactory即可,代码如下:
@Data @AllArgsConstructor @NoArgsConstructor @Slf4j @Component @PropertySource(value = {"classpath:config/custom-profile.yml"}, encoding = "utf-8", factory = YmlPropertySourceFactory.class) @ConfigurationProperties(prefix = "person") public class Person { @Value("${person.name}") private String name; @Value("${person.age}") private int age; @Value("${person.birthday}") private Date birthday; private Listhobby; private Map assets; private Dog dog; } 对应配置文件:
person: name: qlh age: 22 birthday: 2012/04/02 hobby: - 打 - 睡 - 玩 - 学 assets: phone: iphone car: 福特野马 dog: name: 狗 age: 1
测试是否成功@PropertySource指定加载自定义的配置文件,默认只能加载properties格式,但是可以指定factory属性来加载YML格式的配置文件。
同时加载多个配置编写PropertiesController
@RestController @RequestMapping("properties") @Slf4j public class PropertiesController { final Person person; public PropertiesController(Person person) { this.person = person; } @GetMapping("getProperties") public Dict getProperties(){ log.info(person.toString()); return Dict.create().set("person", person); } }浏览器输入:http://localhost:8081/springboot-properties/properties/getProperties验证结果。看到打印类信息,表示加载自定义YML格式的配置文件成功了。
扩展功能
SpringBoot还提供了@importResource注解加载外部配置文件,只不过@importResource通常用于加载Spring的xml配置文件
@importResource使用
Spring Boot提出零xml的配置,因此Spring Boot默认情况下是不会主动识别项目中Spring的xml配置文件。为了能够加载xml的配置文件,Spring Boot提供了@importResource注解,该注解可以加载Spring的xml配置文件,通常加于启动类上。这里就不做赘述了,代码参考下面。
Spring Boot多环境配置//value:Spring的xml配置文件,支持多个。 @importResource(value = {"classpath:config/beans.xml"}) @SpringBootApplication public class SpringbootPropertiesApplication { public static void main(String[] args) { SpringApplication.run(SpringbootPropertiesApplication.class, args); } }
yml多环境配置多环境配置有什么好处呢???
不同环境配置可以配置不同的参数
便于部署,提高效率,减少出错application.yml 主配置文件
server: port: 8081 servlet: context-path: /springboot-properties #配置激活选项 spring: profiles: active: devapplication-dev.yml 开发配置文件
#指定属于哪个环境 spring: profiles: - devapplication-prod.yml 生产配置文件
#指定属于哪个环境 spring: profiles: - propapplication-test.yml 测试配置文件
properties多环境配置#指定属于哪个环境 spring: profiles: - test(1)主配置文件:配置激活选项
spring.profiles.active=dev(2)其他配置文件:指定属于哪个环境(同yml,只不过表现形式是key=value的,三个配置文件分别是:application-dev.properties,application-prod.properties,application-test.properties)
yml多环境配置和properties多环境配置比较Properties配置多环境:需要添加多个配置文件
yml配置多环境:可添加多个配置文件,可不添加,使用---分隔(案例如下面代码)(不建议使用该方法,这样显得配置文件臃肿,强烈建议添加多个配置文件,也不费事。)server: port: 8081 servlet: context-path: /springboot-properties spring: profiles: active: dev --- spring: profiles: - test --- spring: profiles: - prod --- spring: profiles: - dev
激活指定profile一般使用的配置文件
application.yml:是主配置文件,放一些项目通用的配置
application-dev.yml:放平常开发的一些配置,比如说数据库的连接地址、帐号密码等
application-prod.yml:放生产环境的一些配置,比如说数据库的连接地址、帐号密码等
application-test.yml:放测试环境需要用到的参数无论是使用上述多文档块的方式,还是新建application-test.yml文件,都可以在配置文件中指定 spring.profiles.active=test 激活指定的profile。
java -jar XXXX-0.0.1-SNAPSHOT.jar --spring.profiles.active=test-Dspring.profiles.active=test
结束语@SpringBootApplication public class SpringbootPropertiesApplication { public static void main(String[] args) { System.setProperty("spring.profiles.active", "test"); SpringApplication.run(SpringbootPropertiesApplication.class, args); } }感谢阅读小生文章。祝大家早日富可敌国,实现财富自由。
写文不易,一定要点赞、评论、收藏哦,感谢感谢感谢!!!



