六、配置文件占位符
占位符和随机数比较简单,这里就直接贴出代码。需要注意的是:
- 占位符的值必须是完整路径
- 占位符设置默认值,冒号后面不能有空格
Posted yft-javanotes
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot配置文件相关的知识,希望对你有一定的参考价值。
Spring Boot提供了两种常用的配置文件,分别是properties文件和yml文件。
他们的作用都是修改Spring Boot自动配置的默认值。相对于properties文件而言,yml文件更年轻,也有很多的坑。可谓成也萧何败也萧何,yml通过空格来确定层级关系,使配置文件结构更清晰,但也会因为微不足道的空格而破坏了层级关系。
yml是YAML(YAML Ain‘t Markup Language)语言的文件,以数据为中心,比json、xml等更适合做配置文件
yml和xml相比,少了一些结构化的代码,使数据更直接,一目了然。举例:
YAML
server:
port: 8081
XML:
<server> <port>8081</port> </server>
yml和json呢?没有谁好谁坏,合适才是最好的。yml的语法比json优雅,注释更标准,适合做配置文件。json作为一种机器交换格式比yml强,更适合做api调用的数据交换。
k:(空格)v:表示一对键值对(空格必须有);
以空格的缩进程度来控制层级关系。空格的个数并不重要,只要左边空格对齐则视为同一个层级。注意不能用tab代替空格。且大小写敏感。
server:
port: 8081
path: /hello
YAML支持字面值,对象,数组三种数据结构,也支持复合结构。
【字面值】——字符串,布尔类型,数值,日期。
k: v:字面直接来写;
字符串默认不用加上单引号或者双引号;
"":双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
name: "zhangsan \\n lisi":输出;zhangsan 换行 lisi
‘‘:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name: ‘zhangsan \\n lisi’:输出;zhangsan \\n lisi
【对象】
由键值对组成,形如 key:(空格)value 的数据组成。冒号后面的空格是必须要有的,每组键值对占用一行,且缩进的程度要一致。
friends:
lastName: zhangsan
age: 20
也可以使用行内写法:k1: v1, ....kn: vn
friends: lastName: zhangsan,age: 18
【数组】——List、Set
由形如 -(空格)value 的数据组成。短横线后面的空格是必须要有的,每组数据占用一行,且缩进的程度要一致,也可以使用行内写法: [1,2,...n]
pets:
- cat
- dog
- pig
行内写法
pets: [cat,dog,pig]
创建一个Spring Boot 的全局配置文件 application.yml,配置属性参数。
person:
lastName: hello
age: 18
boss: false
birth: 2019/7/14
maps: k1: v1,k2: v2
lists:
- zhangsan
- lisi
dog:
name: 小狗
age: 12
创建实体类Person.java 获取配置文件中的属性值,通过注解@ConfigurationProperties获取配置文件中的指定值并注入到实体类中。
/** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定; * prefix = "person":配置文件中哪个下面的所有属性进行一一映射 * * 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能; * */ @Component @ConfigurationProperties(prefix = "person") public class Person private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; // 省略getter,setter,toString方法
我们可以导入配置文件处理器,以后编写配置就有提示了
<!--导入配置文件处理器,配置文件进行绑定就会有提示--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
创建一个单元测试类:
/** * SpringBoot单元测试; * * 可以在测试期间很方便的类似编码一样进行自动注入等容器的功能 * */ @RunWith(SpringRunner.class) @SpringBootTest public class PersonTest @Autowired private Person person; @Test public void test() System.out.println(person);
注意:在运行测试类之前,要确保spring boot的引导类(主程序)是已启动状态。
properties文件经常用,这里就简单介绍一下。其语法结构形如:key=value。
userinfo.account=zhangsan
userinfo.age=25
userinfo.active=true
userinfo.created-date=2019/07/14 16:54:30
userinfo.map.k1=v1
userinfo.map.k2=v2
userinfo.list=one,two,three
从配置文件中取值注入到实体类中,和YAML是一样的。
/** * 用户信息 * @ConfigurationProperties : 被修饰类中的所有属性会和配置文件中的指定值(该值通过prefix找到)进行绑定 */ @Component @ConfigurationProperties(prefix = "userinfo") public class UserInfo private String account; private Integer age; private Boolean active; private Date createdDate; private Map<String, Object> map; private List<Object> list; // 省略getter,setter,toString方法
注意:
【注意】:spring boot项目中同时存在application.properties和application.yml文件时,两个文件都有效,但是application.properties的优先级会比application.yml高。
Spring Boot通过ConfigurationProperties注解从配置文件中获取属性。从上面的例子可以看出ConfigurationProperties注解可以通过设置prefix指定需要批量导入的数据。支持获取字面值,集合,Map,对象等复杂数据。ConfigurationProperties注解还有其他特么呢?它和Spring的Value注解又有什么区别呢?带着这些问题,我们继续往下看。
ConfigurationProperties注解的优缺点
Value注解的优缺点正好相反,它只能一个个配置注入值;不支持数组、集合等复杂的数据类型;不支持数据校验;对属性名匹配有严格的要求。最大的特点是支持SpEL表达式,使其拥有更丰富的功能。
第一步:导入依赖。若要使用ConfigurationProperties注解,需要导入依赖 spring-boot-configuration-processor;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
第二步:配置数据。在application.yml配置文件中,配置属性参数,其前缀为employee,参数有字面值和数组,用来判断是否支持获取复杂属性的能力;(nick-name是用来判断匹配属性的松散性,若换成nick_name依然可以获取值。)
employee:
nick-name: itachi
email: [email protected]
phone: 1234567
abilities: [java,sql,html]
created_date: 2019/7/14 13:40
第三步:匹配数据。在类上添加注解ConfigurationProperties,并设置prefix属性值为employee。并把该类添加到Spring的IOC容器中。
第四步:校验数据。添加数据校验Validated注解,开启数据校验,测试其是否支持数据校验的功能;
第五步:测试ConfigurationProperties注解是否支持SpEL表达式;
/** * ConfigurationProperties 注解语法类 * 第一步:导入依赖 spring-boot-configuration-processor; * 第二步:把ConfigurationProperties注解修饰的类添加到Spring的IOC容器中; * 第三步:设置prefix属性,指定需要注入属性的前缀; * 第四步:添加数据校验注解,开启数据校验; * * 注意点: * 一、nickName和createdDate在yml配置文件中,对应参数分别是中划线和下划线,用于测试其对属性名匹配的松散性 * 二、email和iphone 测试其支持JSR303数据校验 * 三、abilities 测试其支持复杂的数据结构 */ @Component @ConfigurationProperties(prefix = "employee") @Validated public class ConfigurationPropertiesEntity private String nickName; // 解析成功,支持松散匹配属性 private String email; // @Email //表示phone必须填成email格式。此处解析失败:Binding validation errors on employee private String phone; private List<String> abilities; private Date createdDate; // 解析成功,支持松散匹配属性 // @ConfigurationProperties("#11*2") //语法报错,不支持SpEL表达式:not applicable to field private String operator; // 省略get/set和toString方法
第一步:在属性上添加Value注解,通过$设置参数从配置文件中注入值;
第二步:修改$employee.ceatred_date
中的参数值,改为$employee.ceatredDate
测试是否能解析成功;
第三步:添加数据校验Validated注解,开启数据校验,测试其是否支持数据校验的功能;
第四步:测试Value注解是否支持SpEL表达式;
/** * Value 注解语法类 * 第一步:在属性上添加注解Value注入参数 * 第二步:把Value注解修饰的类添加到Spring的IOC容器中; * 第三步:添加数据校验注解,检查是否支持数据校验; * * 注意点: * 一、nickName和createdDate在yml配置文件中,对应参数分别是中划线和下划线,用于测试其对属性名匹配的松散性 * 二、email和iphone 测试其支持JSR303数据校验 * 三、abilities 测试其支持复杂的数据结构 * * 结论: * 一、createDate取值必须和yml配置文件中的参数保持一致, * 二、既是在iphone上添加邮箱验证注解依然可以通过测试, * 三、不支持复杂的数据结构,提示错误和第一条相同:IllegalArgumentException: Could not resolve placeholder ‘itdragon.abilities‘ in value "$itdragon.abilities" */ @Component @Validated public class ValueEntity @Value("$employee.nick-name") private String nickName; @Value("$employee.email") private String email; @Email @Value("$employee.phone") // 解析成功,并不支持数据校验 private String phone; // @Value("$employee.abilities") //解析错误,并不支持复杂的数据结构 private List<String> abilities; // @Value("$employee.createDate") // 解析错误,并不支持松散匹配属性,必须严格一致 @Value("$employee.created_date") private Date createDate; // Value注解的强大一面:支持SpEL表达式 @Value("#11*2") // 算术运算 private String operator; @Value("#1>2 || 2<=3") // 关系运算 private Boolean comparison; @Value("#systemProperties[‘java.version‘]") //系统配置:os.name private String systemProperties; @Value("#T(java.lang.Math).abs(-18)") // 表达式 private String mapExpression; // 省略get/set和toString()
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
person.last-name=李四
person.age=12
person.birth=2019/7/14
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=dog
person.dog.age=15
如果要在配置类中加载person.properties配置文件,则需要用到@PropertySource
/** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定; * prefix = "person":配置文件中哪个下面的所有属性进行一一映射 * * 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能; * @ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值; * */ @PropertySource(value = "classpath:person.properties") @Component @ConfigurationProperties(prefix = "person") public class Person private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String, Object> maps; private List<Object> lists; private Dog dog; // 省略get/set和toString()方法
编写一个HelloService.java
public class HelloService
编写一个beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="com.pinyougou.service.HelloService"></bean> </beans>
在测试类中测试该配置文件有没有生效:
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBootConfigApplicationTest @Autowired private ApplicationContext context; @Test public void testHelloService() boolean b = context.containsBean("helloService"); System.out.println(b); // false
测试表明,Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
@ImportResource(locations = "classpath:beans.xml") @SpringBootApplication public class SpringbootdemoApplication public static void main(String[] args) SpringApplication.run(SpringbootdemoApplication.class, args);
这时候再次运行testHelloService()测试方法,结果为true。说明自己编写的beans.xml配置文件已经生效了。
总结:
虽然使用@ImportResource能导入我们编写的配置文件,但是SpringBoot并不推荐这种方式,SpringBoot推荐使用全注解的方式来给容器中添加组件。这时候就使用到了@Bean来给容器中添加组件。
为了测试效果明显,将beans.xml删掉,并且将@ImportResource注释掉:
创建一个配置类:
/** * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件。@Configuration可理解为用spring的时候xml里面的<beans>标签。 * @Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文对象) */ @Configuration public class MyAppConfig // 将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
// @Bean标注在方法上(返回某个实例的方法),等价于spring配置文件中的<bean></bean>,作用为:注册bean对象 // @Bean可理解为用spring的时候xml里面的<bean>标签。 @Bean public HelloService helloService() System.out.println("配置了@Bean给容器中添加了组件。。。"); return new HelloService();
再次运行测试类:
注意:
Spring Boot不是spring的加强版,所以@Configuration和@Bean同样可以用在普通的spring项目中。
占位符和随机数比较简单,这里就直接贴出代码。需要注意的是:
ran: # 这里的prefix不能是random,
ran-value: $random.value
ran-int: $random.int
ran-long: $random.long
ran-int-num: $random.int(10)
ran-int-range: $random.int[10,20]
ran-placeholder: placeholder_$ran.ran-value:此处不能有空格,且key为完整路径
/** * 随机数和占位符语法类 */ @Component @ConfigurationProperties(prefix = "ran") public class RandomEntity private String ranValue; // 随机生成一个字符串 private Integer ranInt; // 随机生成一个整数 private Long ranLong; // 随机生成一个长整数 private Integer ranIntNum; // 在指定范围内随机生成一个整数 private Integer ranIntRange;// 在指定区间内随机生成一个整数 private String ranPlaceholder;// 占位符 // 省略getter,setter,toString方法e
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBootYmlApplicationTests @Autowired private RandomEntity randomEntity; @Test public void contextLoads() System.out.println("Random Grammar : " + randomEntity);
我们在主配置文件编写的时候,文件名可以是 application-profile.properties。如:
application-dev.properties
application-prod.properties
application.properties主配置文件
运行主程序时,默认使用的是application.properties主配置文件的端口号:8080
当我们要激活指定的profile时,比如要激活开发环境的8081端口,可以在主配置文件中添加spring.profiles.active=dev
server: port: 8080 spring: profiles: active: prod #指定使用生产环境运行 --- server: port: 8081 spring: profiles: dev --- server: port: 8082 spring: profiles: prod
除了在配置文件中通过代码来激活指定的profile,还可以通过命令行和指定虚拟机参数的方式来激活指定的profile。
【命令行】
可以直接在测试的时候,配置传入命令行参数:
此外,如果将项目package后,也可以通过命令行的方式来指定profile:
【虚拟机参数】
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
file:./config/
file:./
classpath:/config/
classpath:/
如果存在多个配置文件,则严格按照优先级进行覆盖,最高者胜出。如下图1~4优先级从高到低:
我们还可以通过spring.config.location来改变默认的配置文件位置。
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
以上是关于Spring Boot配置文件的主要内容,如果未能解决你的问题,请参考以下文章
黑马_13 Spring Boot:04.spring boot 配置文件