第一篇介绍了
SpringBoot
由来及构建方式,通过第一章的教程我们对SpringBoot
不再感到陌生,可以发现SpringBoot
虽然干掉了 XML 但未做到 零配置,它体现出了一种 ==约定优于配置,也称作按约定编程==,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,这种方式简单又不失灵活。 一般情况下默认的配置足够满足日常开发所需,但在特殊的情况下,我们往往需要用到 自定义属性配置、自定义文件(配置文件)配置、多环境配置、外部命令引导 等一系列功能。不用担心,这些SpringBoot
都替我们考虑好了,我们只需要遵循它的规则配置即可
环境/版本一览:
- 开发工具:Intellij IDEA 2018.2.2
- springboot: 2.0.5.RELEASE
- jdk:1.8.0_171
- maven:3.3.9
文件处理器的使用
为了让 Spring Boot
更好的生成配置元数据文件,我们需要添加如下依赖(该依赖可以不添加,但是在 IDEA 和 STS 中不会有属性提示,没有提示的配置就跟你用记事本写代码一样苦逼,出个问题弄哭你去),该依赖只会在编译时调用,所以不用担心会对生产造成影响…
1 | <!--导入配置文件处理器,配置文件进行绑定就会有提示--> |
自定义属性值
通过@ConfigurationProperties的prefix
值绑定,自定义属性便可与类中的属性一样映射,如果导入配置文件处理器,那么在配置文件中就可以有提示了。
效果
注意:如果没有提示则重新 编译 一下即可
经测试,该处理器只对 application.yml、application.properties 有效,对如 test.properties 无效,所以当我们需要使用的时候,可以先用 application.properties 命名配置文件,写完改为 xxx.properties
即可。
(这方法看一下,可以在后面测试中使用,挺方便的)
1、配置文件
SpringBoot 使用一个 全局 的配置文件,配置文件名是 固定 的;该配置文件可以对一些默认配置进行修改
两种写法
- application.properties
- application.yml
析: yml 是 YAML (YAML Ain’t Markup Language)语言的文件,以数据为中心,比 json,xml 等更 适合 做配置文件。语法规范可参考 http://yaml.org/
示例
application.properties
1
server.port: 8081
application.yml
1
2server:
port: 8081
2、YAML
2.1、基本语法
k:(空格)v:表示一对键值对(空格必须有);
它是以 空格 的缩进来控制 层级 关系;只要是左对齐的一列数据,都是同一个层级的
1 | server: |
注:属性和值也是大小写敏感;
2.2、值的写法
2.2.1、字面量
普通的值(数字,字符串,布尔)
k: v
:字面直接来写;
字符串 默认不用加 上 单引号 或者 双引号;加了的话有特殊意义,如下
“”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
name: “zhangsan \n lisi”:输出;zhangsan 换行 lisi
‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi
2.2.2、对象、Map
k: v
:写对象或集合的属性和值的关系;注意缩进
普通写法
1 | friends: |
行内写法
1 | friends: {lastName: zhangsan, age: 18} |
2.2.3、数组、List、Set
用
-
值表示数组中的一个元素
普通写法
1 | # 用`-`值表示数组中的一个元素,后面有一个空格 |
行内写法
1 | pets: [cat,dog,pig] |
3、配置文件值注入
3.1、全局配置文件值注入
全局配置文件: application.properties 与 application.yml ,这里以 application.yml 为例
application.yml
1 | #自定义属性值 |
Component(@Value)
其他组件如:@Controller、@Service 也可以和 @Value 一起用
1 | package com.fatal.config; |
Component(@ConfigurationProperties)
一定要加上注解 @Component
1 | package com.fatal.config; |
1 | package com.fatal.config; |
Controller
1 | package com.fatal.controller; |
3.1.1、@Value获取值和@ConfigurationProperties获取值(方式)比较
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL(spring表达式语言) | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
松散绑定(松散语法):比如实体类有个属性叫 lastName,那么在配置文件中 lastName 、last-name 两种写法都是正确的。
复杂类型封装:属性又是一个实体,多层嵌套(复用)
注意:不管配置文件是 yml 还是 properties 他们 都 能获取到值;
3.1.2、使用场景
@Value
我们只是在某个业务逻辑中需要获取配置文件中的某项值,使用@Value;
@ConfigurationProperties
我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
3.2、配置文件注入值数据校验
以全局为例,校验的话对自定义和全局都有效。
application.yml
1 | #自定义属性值 |
Component(@ConfigurationProperties+@Validated)
1 | package com.fatal.config; |
Controller
1 |
|
分析:
在配置类上加上注解 @Validated ,然后在属性上加上 校验注解 (javax.validation.constraints.*)。如果校验失败,项目启动时就会报错,例如邮箱 格式不正确 的话,就会出现如下 报错
1 | Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'fatal' to com.fatal.config.Fatal3 failed: |
3.3、自定义配置文件值注入
上面的配置文件值注入我们都是把配置数据放在 application.yml 中,但是一般情况下,我们都不希望把自定义数据放到 application.yml 中(这样数据较乱),这时候我们可以自定义配置文件,如:test.properties;
test.properties
1 | fatal.name=fatal |
Component(@PropertySource)
1 | package com.fatal.config; |
分析:
用 application.yml 或者 application.properties 来给配置类注入值,不需要我们指定配置文件的位置,SpringBoot 默认会加载;而当我们使用自定义配置文件的时候,我们需要告诉SpringBoot该配置类与哪个配置文件进行数据映射,这时候我们可以用注解 @PropertySource() 注解,并用其属性 value 指定一个(或多个)配置文件。(需要 注意 的是,classpath 与 文件路径中间不能有空格)
4、配置文件占位符
4.1、使用随机数
1 | ${random.value} |
4.2、属性配置占位符
可以在配置文件中引用前面配置过的属性
${fatal.age:默认值} 来指定找不到属性时的默认值
5、多环境化配置(两种方式)
在真实的应用中,常常会有多个环境(如:开发,测试,生产等),不同的环境数据库连接都不一样,这个时候就需要用到spring.profile.active
的强大功能了,它的格式为 application-{profile}.yml/properties
,这里的 application
为前缀不能改,{profile}
是我们自己定义的。
5.1、多个文件写
application-dev.properties
1 | server.servlet.context-path=/dev |
application-test.properties
1 | server.servlet.context-path=/test |
application-prod.properties
1 | server.servlet.context-path=/prod |
在 application.properties
配置文件中写入 spring.profiles.active=dev
,这个时候我们再次访问 http://localhost:8080/getPropertyValue1 就没用处了,因为我们设置了它的context-path=/dev
,所以新的路径就是 http://localhost:8080/dev/getPropertyValue1 ,由此可以看出来我们激活不同的配置读取的属性值是不一样的
5.2、yml支持多文档块方式(同一文件写)
1 | server: |
5.3、外部命令引导
前面两种方式都是基于配置文件层面的,那么有没有办法外部引导呢,假设这样的场景,我们对已经开发完成的代码打包发布,期间在测试环境测试通过了,那么即可发布上生产,这个时候是修改application.properties
的配置方便还是直接在命令参数配置方便呢,毫无疑问是后者更有说服力。默认情况下,SpringApplication
会将命令行选项参数(即:––property,如––server.port=9000)添加到Environment,命令行属性始终优先于其他属性源。
如何测试?
以 yml 的多文档块方式为例
进入到项目目录,此处以我本地目录为主:
E:/java/IdeaProjects2p0-learni/springboot2ng/chapter2
然后打开 cmd 程序,不会在当前目录打开 cmd 的请自行百度,输入:
mvn package
打包完毕后进入到:
E:/java/IdeaProjects2p0-learni/springboot2ng/chapter2/target
目录中去,我们可以发现一个名为chapter2-0.0.1-SNAPSHOT.jar 的包接着在target 打开 cmd 程序,输入:
java -jar chapter2-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev --fatal.age=32
。仔细观察spring.profiles.active=dev 、fatal.age=32 这俩配置的键值是不是似曾相识,对,它表示用命令行自定义配置属性,它会覆盖掉配置文件中的属性值(不认识的请从开头认真阅读)最后输入测试地址:http://localhost:8083/getPropertyValue1 我们可以发现返回的 JSON 和下面相似就表示正确
6、配置文件的加载位置
SpringBoot 启动会扫描以下位置的 application.properties 或 application.yml 文件作为 SpringBoot 的 默认 配置文件
1 | -file:/config/ # 当前项目的根目录的config文件夹下 |
==注意==:当项目为多模块项目的时候,file 指的是 父工程 的根目录下,放子工程根目录没用。
规则
- (上到下)优先级由高到底,相同的配置项,高优先级的配置会 覆盖 低优先级的配置;
- 如果出现 不同的配置项,会形成 互补配置 共同起作用;
另外
我们还可以通过 spring.config.additional-location(配置项) 来改变默认配置文件的加载位置
项目打包好以后,我们可以使用 命令行参数 的形式,启动项目的时候来指定配置文件的加载位置;新配置文件 与 默认加载的这些配置文件 ==共同作用形成== 互补配置
测试
1. classpath:/config/ 覆盖 classpath:/
2. file:/ 覆盖 classpath:/config/
3. file:/config/ 覆盖 file:/
4. 外部配置文件
D:\application.properties
命令行加参数 ==spring.config.additional-location==
1 | java -jar chapter2-0.0.1-SNAPSHOT.jar --spring.config.additional-location=D:\application.properties |
注:如果使用 spring.config.location 的话,那么默认包下的全局配置文件无效
步骤
编辑 D:\application.properties
1
fatal.name=outward/properties
打包
运行
页面
补充:命令行参数
所有的配置都可以在命令行上进行指定
1 | java -jar chapter2-0.0.1-SNAPSHOT.jar --server.port=9090 |
多个配置用空格分开; --配置项=值
7、配置加载顺序(覆盖、互补)
SpringBoot也可以从以下位置加载配置; 优先级从高到低;高优先级的配置==覆盖==低优先级的配置,所有的配置会形成==互补==配置
规则
在 spring.profiles.active指定一个环境后,属性的优先级如下:
由jar包外向jar包内进行寻找;
顺序为:包外的config下的优先级最高(在config文件中也是优先profile)
优先加载带profile
jar 包外部 的 application-{profile}.properties 或 application.yml(带spring.profile) 配置文件
jar 包内部 的 application-{profile}.properties 或 application.yml(带spring.profile) 配置文件
再来加载不带profile
jar 包外部 的 application.properties 或 application.yml(不带spring.profile) 配置文件
jar 包内部 的 application.properties或 application.yml(不带spring.profile) 配置文件
所有支持的配置加载来源:参考官方文档
测试
- 打包
- 创建两个配置文件,分别为 application.properties 和 application-dev.properties
- 运行(java -jar chapter2-0.0.1-SNAPSHOT.jar)
包内外的 application-dev.properties
如果配置项不同,则形成互补。
总结
@ConfigurationProperties:用于 配置文件 与 配置类 数据映射;
其属性 prefix:与配置文件中
prefix
下的所有属性进行 一 一 映射;在某个业务逻辑中需要获取配置文件中的 某项值,使用@Value;编写了一个
javaBean
来和配置文件进行映射,我们就直接使用@ConfigurationProperties
;@PropertySource
加载指定配置文件;Controller 和 Component 都是Spring 容器中的组件;
在项目根目录下,
mvn package
可以打包,在生成包所在目录下,java -jar chapter2-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev --fatal.age=32
可以自定义参数运行包
SpringBoot
的知识已经有前辈在我们之前探索了。比较喜欢的博主有:唐亚峰 | Battcn、方志朋的专栏、程序猿DD、纯洁的微笑。对这门技术感兴趣的可以去他们的博客逛逛。谢谢他们的分享~~
以上文章是我用来学习的Demo
,都是基于 SpringBoot2.x
版本。
源码地址: https://github.com/ynfatal/springboot2-learning/tree/master/chapter2