认识SpringBoot2.X
准备
Spring
Spring 是一个开源框架,2003 年兴起的一个轻量级的 Java 开发框架,作者:Rod Johnson 。
Spring 是为了解决企业级应用开发的复杂性而创建的,简化开发。
为了降低 Java 开发的复杂性,Spring 采用了以下 4 种关键策略:
- 基于 POJO 的轻量级和最小侵入性编程,所有东西都是 bean;
- 通过 IOC,依赖注入(DI)和面向接口实现松耦合;
- 基于切面(AOP)和惯例进行声明式编程;
- 通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;
SpringBoot
学过 javaweb 的同学就知道,开发一个 web 应用,从最初开始接触 Servlet 结合 Tomcat, 跑出一个 Hello Wolrld 程序,是要经历特别多的步骤;后来就用了框架 Struts,再后来是 SpringMVC,到了现在的 SpringBoot,过一两年又会有其他 web 框架出现;框架不断的演进,然后自己开发项目所有的技术也在不断的变化.
SpringBoot 就是一个 javaweb 的开发框架,和 SpringMVC 类似,对比其他 javaweb 框架的好处,官方说是简化开发,约定大于配置, you can “just run”,能迅速的开发 web 应用,几行代码开发一个 http 接口。
所有的技术框架的发展似乎都遵循了一条主线规律:从一个复杂应用场景衍生一种规范框架,人们只需要进行各种配置而不需要自己去实现它,这时候强大的配置功能成了优点;发展到一定程度之后,人们根据实际生产应用情况,选取其中实用功能和设计精华,重构出一些轻量级的框架;之后为了提高开发效率,嫌弃原先的各类配置过于麻烦,于是开始提倡“约定大于配置”,进而衍生出一些一站式的解决方案。这就是 Java 企业级应用-> J2EE-> spring-> springboot 的过程。
随着 Spring 不断的发展,涉及的领域越来越多,项目整合开发需要配合各种各样的文件,慢慢变得不那么易用简单,违背了最初的理念,甚至人称配置地狱。
Spring Boot 正是在这样的一个背景下被抽象出来的开发框架,目的为了让大家更容易的使用 Spring . 更容易的集成各种常用的中间件或开源软件;
Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速. 敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。
Spring Boot 以 约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis. MongoDB. Jpa. RabbitMQ. Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。简单来说就是 SpringBoot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包,spring boot 整合了所有的框架 。
Spring Boot 优点
- 为所有 Spring 开发者更快的入门
- 开箱即用,提供各种默认配置来简化项目配置
- 内嵌式容器简化 Web 项目
- 没有冗余代码生成和 XML 配置的要求
HelloWorld
下面将快速的创建一个 Spring Boot 应用,并且实现一个简单的 Http 请求处理。
通过这个例子对 Spring Boot 有一个初步的了解,并体验其结构简单. 开发快速的特性。
环境准备:
- java version “1.8.0_181”
- Maven-3.6.1
- SpringBoot 2.x
- 开发工具:IDEA
创建基础项目
- Spring 官方提供了非常方便的工具让我们快速构建应用
- Spring Initializr:https://start.spring.io/
- 阿里开发脚手架:https://start.aliyun.com/
方式一
使用 Spring Initializr 的 Web 页面创建项目
填写项目信息
点击”Generate Project“按钮生成项目;下载此项目
解压项目包,并用 IDEA 以 Maven 项目导入,一路下一步即可,直到项目导入完毕。
如果是第一次使用,可能速度会比较慢,包比较多. 需要耐心等待一切就绪。
方式二
创建一个 IDEA 新项目 Maven 项目
专业版可以选择 spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现
填写项目信息
选择初始化的组件(初学勾选 Web 即可)
填写项目路径
等待项目构建成功
通过上面步骤完成了基础项目的创建。就会自动生成以下文件。
程序的主启动类
一个 application.properties 配置文件
一个 测试类
一个 pom.xml
pom.xml 分析
打开 pom.xml,看看 Spring Boot 项目的依赖:
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<!-- 父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!-- web场景启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot单元测试 -->
<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>
</dependencies>
<build>
<plugins>
<!-- 打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
编写一个 http 接口
在主程序的同级目录下,新建一个 controller 包,一定要在同级目录下,默认扫描启动类下的子包。
在包中新建一个 HelloController 类
1
2
3
4
5
6class HelloController {
public String hello() {
return "Hello World";
}
}编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回;控制台输出了 Tomcat 访问的端口号!
将项目打成 jar 包
点击 maven 的 package
发现 IDEA 打包时,会跑测试用例,跑不过,就会打包失败报错。如果遇到以上错误,可以配置打包时跳过项目运行测试用例,也可也配置
mvn package -Dmaven.test.skip=true
-DskipTests
,不执行测试用例,但编译测试用例类生成相应的 class 文件至 target/test-classes 下-Dmaven.test.skip=true
,不执行测试用例,也不编译测试用例类1
2
3
4
5
6
7
8
9
10
11
12
13<!--
在工作中,很多情况下我们打包是不想执行测试用例的
可能是测试用例不完事,或是测试用例会影响数据库数据
跳过测试用例执
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--跳过项目运行测试用例-->
<skipTests>true</skipTests>
</configuration>
</plugin>
如果打包成功,则会在 target 目录下生成一个 jar 包, jar 包后,就可以在任何地方运行了
Banner 定义
更改启动时显示的 banner 图案: 到项目下的 resources 目录下新建一个 banner.txt 即可。
图案生成网站,生产后拷贝到文件中即可
http://www.degraeve.com/img2txt.php
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# banner.txt的内容:
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////
关闭 banner
设置 setBannerMode
1
2
3
4
5public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
配置文件
配置文件的作用 : 修改 SpringBoot 自动配置的默认值 (SpringBoot 在底层已经配置好的属性)。
SpringBoot 使用一个全局的配置文件 , 配置文件名称是固定的.
application.properties
:key=value
application.yml
:key:空格 value
注意:如果 yml 和 properties 同时都配置,并且没有激活其他环境 , 默认会使用 properties 配置文件
比如我们可以在配置文件中修改 Tomcat 默认启动的端口号!
1
server.port=8081
在代码里指定配置文件
1
2
3
4
5
6
7
public class SpringbootrestdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootrestdemoApplication.class, args);
}
}
yaml 概述
YAML 是 “YAML Ain’t a Markup Language” (YAML 不是一种标记语言)的递归缩写。
在开发的这种语言时,YAML 的意思其实是:”Yet Another Markup Language”(仍是一种标记语言), 这种语言以数据为中心,而不是以标记语言为重点
以前的配置文件,大多数都是使用 xml 来配置;比如一个简单的端口配置,使用 yaml 标记数据更轻便
1
2
3
4
5
6
7
8# 传统xml配置:
<server>
<port>8081<port>
</server>
# yaml配置:
server:
port: 8081
yaml 基础语法
- YAML 语法要求严格!
- 空格不能省略
- 以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。
- 属性和值的 大小写十分敏感 的。
字面量:
普通的值: 数字,布尔值,字符串
字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号
注意:
“ ”
双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;- 比如 :
name: "张 \n 三"
,结果会输出二行
- 比如 :
''
单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出- 比如 :
name: "张 \n 三’
输出 :张 \n 三
- 比如 :
对象、Map
在下一行来写对象的属性和值得关系,注意缩进;比如:
1
2
3student:
name: qinjiang
age: 3行内写法
1
student: {name: qinjiang,age: 3}
数组
用
-
值表示数组中的一个元素, 比如:1
2
3
4pets:
- cat
- dog
- pig行内写法
1
pets: [cat,dog,pig]
properties 配置文件写法
1
2com.code.services[0]=service1
com.code.services[1]=service2
@value 指定值
使用
@Value
给 bean 注入属性值1
2
3
4
5
6
7
8
9
10
11package top.fulsun.helloworld.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//注册 bean 到容器中
public class Dog {
private String name;
private Integer age;
//有参无参构造、get、set 方法、toString()方法
}在 SpringBoot 的测试类下注入狗狗输出一下;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class HelloworldApplicationTests {
// 多个 Dog 示例时候 @Qualifier("name")注解来指明注入的实例
//将狗狗自动注入进来
private Dog dog;
void contextLoads() {
//打印输出
System.out.println(dog);
}
}结果成功输出,@Value 注入成功,这是我们原来的办法对吧。
注入 yaml 的值
- yaml 文件更强大的地方在于,他可以给我们的 实体类直接注入匹配值,类的字段必须有公共 setter 方法。
在 springboot 项目中的 resources 目录下新建一个文件 application.yml
编写一个实体类 Dog;
1
2
3
4
5
6
7
8
9
10package top.fulsun.helloworld.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//注册 bean 到容器中
public class Dog {
private String name;
private Integer age;
//有参无参构造、get、set 方法、toString()方法
}我们在编写一个复杂一点的实体类:Person 类
1
2
3
4
5
6
7
8
9
10
11//注册 bean 到容器中
public class Person {
private String name;
private Integer age;
private Boolean isHappy;
private Date birth;
private Map<String,Object> map;
private List<Object> lists;
private Dog dog;
//有参无参构造、get、set 方法、toString()方法
}我们来使用 yaml 配置的方式进行注入,编写一个 yaml 配置!
1
2
3
4
5
6
7
8
9
10
11
12
13person:
name: fulsun
age: 3
happy: false
birth: 2020/02/02
lists:
- eat
- sleep
- code
dog:
name: 旺旺
age: 2
map: { k1: v1, k2: v2 }我们刚才已经把 person 这个对象的所有值都写好了,我们现在来注入到我们的类中!
@ConfigurationProperties
作用:将配置文件中配置的每一个属性的值,映射到这个组件中;prefix = “person”
: 将配置文件中的 person 下面的所有属性一一对应- 配置文件的 key 值 和 属性的值设置为不一样,则结果会输出为 null,注入失败
1
2
3
4
5
6
7
8
9
10
11//注册 bean
public class Person {
private String name;
private Integer age;
private Boolean isHappy;
private Date birth;
private Map<String,Object> map;
private List<Object> lists;
private Dog dog;
}更具 IDEA 提示,springboot 配置注解处理器没有找到,可以查看文档,找到一个依赖!
导入配置文件处理器
1
2
3
4
5
6<!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
确认以上配置都 OK 之后,我们去测试类中测试一下:
新建测试类
1
2
3
4
5
6
7
8
9
10
class HelloworldApplicationTests {
Person person; //将 person 自动注入进来
public void contextLoads() {
System.out.println(person); //打印 person 信息
}
}结果:所有值全部注入成功!
配置文件处理器
Spring Boot Configuration Processor 会完成自动补全
当我们在 application.properties 和 application.yml 中写配置的时候会有自动提醒, 重新 build 项目之后,configuration processor 会为我们在 META-INF 下创建一个 JSON 文件:
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{
"groups": [
{
"name": "com.code",
"type": "top.fulsun.test.FooProperties",
"sourceType": "top.fulsun.test.FooProperties"
}
],
"properties": [
{
"name": "com.code.age",
"type": "java.lang.Integer",
"sourceType": "top.fulsun.test.FooProperties"
},
{
"name": "com.code.foo",
"type": "java.lang.String",
"sourceType": "top.fulsun.test.FooProperties"
},
{
"name": "com.code.name",
"type": "java.lang.String",
"sourceType": "top.fulsun.test.FooProperties"
}
],
"hints": []
}configuration processor 允许我们标记某一个属性为 deprecated, 我们可以通过添加
@DeprecatedConfigurationProperty
注解到字段的 getter 方法上,来标示该字段为 deprecated,重新 build 项目后,当我们再编写配置文件时,已经给出了明确 deprecated 提示:1
2
3
4
5
6
7
8
9
10{
"name": "com.code.name",
"type": "java.lang.String",
"sourceType": "top.fulsun.test.FooProperties",
"deprecated": true,
"deprecation": {
"reason": "change name ",
"replacement": "none"
}
}
激活 @ConfigurationProperties
需要让 Spring 知道我们的 @ConfigurationProperties 类存在,以便将其加载到应用程序上下文中
我们可以通过下面几种方式将其添加到应用上下文中
可以通过添加
@Component
注解让 Component Scan 扫描到,只有当类所在的包被 Spring@ComponentScan
注解扫描到才会生效,默认情况下,该注解会扫描在主应用类下的所有包结构我们也可以通过 Spring 的 Java Configuration 特性实现同样的效果:
1
2
3
4
5
6
7
8
9
public class PropertiesConfig {
public FooProperties fooProperties(){
return new FooProperties();
}
}可以使用
@EnableConfigurationProperties
注解让我们的类被 Spring Boot 所知道,在该注解中其实是用了@Import(EnableConfigurationPropertiesImportSelector.class)
实现1
2
3
4
5
6
7
8
9
10// 这里一定要开启配置生效
public class DemoApplication {
// 需要从容器中获取并注入此类
private Person person;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
激活一个 @ConfigurationProperties 类的最佳方式是什么?
- 所有上述方法都同样有效。建议模块化你的应用程序, 每个模块提供自己的
@ConfigurationProperties
类,只提供它需要的属性。这使得在不影响其他模块的情况下重构一个模块中的属性变得容易。 - 不建议在应用程序类本身上使用
@EnableConfigurationProperties
,是在特定于模块的 @Configuration 类上使用@EnableConfigurationProperties
,该类也可以利用包私有的可见性对应用程序的其余部分隐藏属性。
- 所有上述方法都同样有效。建议模块化你的应用程序, 每个模块提供自己的
注意
属性配置错误的值时, 如定义 boolean,注入时配置文件填写为 string 类型,不希望 Spring Boot 应用启动失败,我们可以设置
ignoreInvalidFields
属性为 true (默认为 false)1
2
3
4
5
6
7
8
9
public class FooProperties {
private String foo;
private String name;
private Integer age;
// 出现问题 Spring Boot 将会设置 enabled 字段为我们在 Java 代码里设定好的默认值。
// 如果我们没有设置默认值,enabled 将为 null,
private Boolean enable = Boolean.TRUE;
}application.properties 文件提供了多余属性
默认情况下,Spring Boot 会忽略那些不能绑定到
@ConfigurationProperties
类字段的属性然而,当配置文件中有一个属性实际上没有绑定到
@ConfigurationProperties
类时,我们可能希望启动失败。为了实现上述情况,我们仅需要将
ignoreUnknownFields
属性设置为 false (默认是 true)1
ignoreUnknownFields
未来 Spring Boot 的版本中会被标记为 deprecated.因为我们可能有两个带有@ConfigurationProperties
的类,同时绑定到了同一个命名空间 (namespace) 上,其中一个类可能知道某个属性,另一个类却不知道某个属性,这样就会导致启动失败.
文件占位符
- 配置文件还可以编写占位符生成随机数
随机数
${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int[1024,65536]}
获取之前配置的值
如果没有可以指定默认值
1
2
3
4
5
6
7
8
9
10
11
12
13person:
name: fulsun${random.uuid}
age: ${random.int}
happy: false
birth: 2020/02/02
lists:
- eat
- sleep
- code
dog:
name: ${person.hello:旺旺}_dog # 没有person.hello就使用旺旺
age: 2
map: { k1: v1, k2: v2 }
properties 文件注入
我们上面采用的 yaml 方法都是最简单的方式,开发中最常用的;也是 springboot 所推荐的!
配置文件除了 yml 还有我们之前常用的 properties
注意: properties 配置文件在写中文的时候,会有乱码 , 我们需要去 IDEA 中 settings–> FileEncodings 中配置编码格式为 UTF-8
新建一个实体类 User
1
2
3
4
5
6
7
8//注册 bean
public class User {
private String name;
private int age;
private String sex;
//......
}编辑配置文件 user.properties
1
2
3user1.name=zhangsan
user1.age=18
user1.sex=男我们在 User 类上使用@Value 来进行注入!
@PropertySource
:加载指定的配置文件;@configurationProperties
:默认从全局配置文件 application.properties 中获取值;1
2
3
4
5
6
7
8
9
10
11//注册 bean
public class User {
//直接使用@value
//从配置文件中取值
private String name;
// #{SPEL} Spring 表达式
private int age;
// 字面量
private String sex;
}
Springboot 测试
测试类
1
2
3
4
5
6
7
8
9
10
11
12
class DemoApplicationTests {
User user;
public void contextLoads() {
System.out.println(user);
}
}结果正常输出:
@PropertySource
Spring 框架提供了 PropertySource 注解,目的是加载指定的属性文件, 可以加载 properties 配置文件的,不能加载 YAML 配置文件;
value:加载 classpath 路径下的 test.properties 配置文件;
ignoreResourceNotFound:当指定的配置文件不存在是否报错,默认是 false ; 比如上文中指定的加载属性文件是 test.properties。如果该文件不存在,则 ignoreResourceNotFound 为 true 的时候,程序不会报错,如果 ignoreResourceNotFound 为 false 的时候,程序直接报错。实际项目开发中,最好设置 ignoreResourceNotFound 为 false。该参数默认值为 false;
encoding:用于指定读取属性文件所使用的编码,我们通常使用的是 UTF-8;
name:这个值在 Springboot 的环境中必须是唯一的,如果不设置,则值为:“class path resource [test.properties]”;此值也可以不用设置;若想深入研究,可查资料继续研究;
注入方式对比
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303 数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
@ConfigurationProperties
只需要写一次即可 ,@Value
则需要每个字段都添加- 松散绑定:比如我的 yml 中写的 last-name(- 后面跟着的字母默认是大写),Bean 中有 lastName 也可以注入成功。
- JSR303 数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
- 复杂类型封装,yml 中可以封装对象 , 使用 value 就不支持
- 配置 yml 和配置 properties 都可以获取到值 , 强烈推荐 yml;
- 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value
- 如果我们专门编写了一个 JavaBean 来和配置文件进行一一映射,就直接@configurationProperties
yaml 松散绑定
Bean 的属性名和 yaml 中的表示方式支持使用:
- 驼峰式、下划线(_)、短横线(-) 后第一个表示大写字母
如 Bean 中属性的写法为
person.firstName
- 方式一:
person.first-name
- 方式二:
person.first_name
- 方式一:
如 Bean 中属性的写法为
person.first_name
- 方式一:
person.first-name
- 方式二:
person.firstName
- 方式一:
JSR303 数据校验
依赖
1
2
3
4<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>Springboot 中可以用
@validated
来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的 name 只能支持 Email 格式;1
2
3
4
5
6
7
8
9import javax.validation.constraints.Email;
//注册 bean
//数据校验
public class Person {
//name 必须是邮箱格式
private String email;
}配置文件
1
2person:
email: ABC123
常见参数
1 | @NotNull(message="名字不能为空") |
jar 包下查看
Duration
Spring Boot 内置支持从配置参数中解析 durations (持续时间),官网文档 给出了明确的说明
我们既可以配置毫秒数数值,也可配置带有单位的文本, 配置 duration 不写单位,默认按照毫秒来指定,我们也可已通过 @DurationUnit 来指定单位:
1
2
3
4
5
6
7
8
9
10
private Duration duration;
ns for nanoseconds (纳秒)
us for microseconds (微秒)
ms for milliseconds (毫秒)
s for seconds (秒)
m for minutes (分)
h for hours (时)
d for days (天)
DataSize
与 Duration 的用法一毛一样,默认单位是 byte (字节),可以通过 @DataSizeUnit 单位指定:
1
2
3
4
5
6
7
8
9
10
private DataSize maxAttachmentSize = DataSize.ofMegabytes(2);
常见单位如下:
B for bytes
KB for kilobytes
MB for megabytes
GB for gigabytes
TB for terabytes
自定义类型
有些情况,我们想解析配置参数到我们自定义的对象类型上,假设,我们我们设置最大包裹重量:
1
private Weight maxAttachementWeight;
可以模仿 DataSize 和 Duration 创造自己的 converter (转换器)
1
2
3
4
5
6
7
8
9import org.springframework.core.convert.converter.Converter;
public class WeightConverter implements Converter<String,Weight> {
public Weight convert(String s) {
return null;
}
}将其注册到 Spring Boot 上下文中,
@ConfigurationPropertiesBinding
注解是让 Spring Boot 知道使用该转换器做数据绑定1
2
3
4
5
6
7
8
9
public class PropertiesConfig {
public WeightConverter weightConverter(){
return new WeightConverter();
}
}
多环境切换
- 实际开发中存在多种环境,profile 是 Spring 对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;
- dev 环境:
application-dev.properties
- test 环境:
application-test.properties
- prod 环境:
application-prod.properties
- dev 环境:
多配置文件
- 主配置文件编写的时候,文件名可以是
application-{profile}.properties/yml
, 用来指定多个环境版本;
properties 配置
application-test.properties
代表测试环境配置application-dev.properties
代表开发环境配置但是 Springboot 并不会直接启动这些配置文件,它 默认使用
application.properties
主配置文件;我们需要通过一个配置来选择需要激活的环境:
1
2
3#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev
yml 文档块方式
和 properties 配置文件中一样,但是使用 yml 使用三条短线
---
可以作为分隔文档块,不需要创建多个配置文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20server:
port: 8080
servlet:
context-path: demo #配置项目的访问路径
#选择要激活那个环境块
spring:
profiles:
active: prod #激活prod生产环境,因此端口为8084
server:
port: 8083
spring:
profiles: dev #配置环境的名称
server:
port: 8084
spring:
profiles: prod #配置环境的名称
激活指定 profile
在 properties 配置文件中指定
spring.profiles.active=dev
命令行:在最后加上
--spring.profiles.active=dev
1
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
虚拟机参数 vmoption:
-Dspring.profiles.active=dev
配置文件加载位置
外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!
springboot 启动会扫描一下位置的
application.properties
或application.yml
文件作为默认配置文件, file 指的是项目根目录。优先级 位置 描述 优先级 1 file:./config/ 工程项目/config 高 2 file:./ 工程项目 较高 3 classpath:/config/ resources/config 较低 4 classpath:/ resources 低 优先级由高到低,高优先级的配置会覆盖低优先级的配置;
SpringBoot 会从这四个位置全部加载主配置文件; 互补配置 ;
外部配置加载顺序
SpringBoot 也可以从以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
常用的 11 个位置 (优先级从高到低)
命令行参数:所有的配置都可以在命令行上进行指定, 多个配置用空格分开;
--配置项=值
1
2
3java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
# 可以在代码中通过 setAddCommandLineProperties 来禁用
SpringApplication.setAddCommandLineProperties(false).来自 java: comp/env 的 JNDI 属性
Java 系统属性(System.getProperties())
操作系统环境变量
RandomValuePropertySource 配置的 random.*属性值
Jar 包寻找: 顺序由 jar 包外向 jar 包内进行寻找, 优先加载带 profile, 再来加载不带 profile
- jar 包外部的 application-{profile}.properties 或 application.yml(带 spring.profile)配置文件
- jar 包内部的 application-{profile}.properties 或 application.yml(带 spring.profile)配置文件
- jar 包外部的 application.properties 或 application.yml(不带 spring.profile)配置文件
- jar 包内部的 application.properties 或 application.yml(不带 spring.profile)配置文件
@Configuration 注解类上的@PropertySource
通过 SpringApplication.setDefaultProperties 指定的默认属性
运维小技巧
可以指定位置加载配置文件:通过
spring.config.location
来改变默认的配置文件位置项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高
1
java -jar spring-boot-config.jar --spring.config.location=F:/application.propert
bootstrap 与 application
加载顺序: 这里主要是说明 application 和 bootstrap 的加载顺序。
- bootstrap.yml(bootstrap.properties)先加载
- application.yml(application.properties)后加载
- bootstrap.yml 用于应用程序上下文的引导阶段。
- bootstrap.yml 由父 Spring ApplicationContext 加载。
- 父 ApplicationContext 被加载在 application.yml 的之前。
配置区别
bootstrap.yml 和 application.yml 都可以用来配置参数。
bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
application.yml 可以用来定义应用级别的,如果搭配 spring-cloud-config 使用 application.yml 里面定义的文件可以实现动态替换。
使用 Spring Cloud Config Server 时,应在 bootstrap.yml 中指定:
1
2spring.application.name
spring.cloud.config.server.git.uri
一些加密/解密信息
实例 bootstrap.yml :
1
2
3
4
5
6
7
8
9
10
11
12
13
14spring:
application:
name: service-a
cloud:
config:
uri: http://127.0.0.1:8888
fail-fast: true
username: user
password: ${CONFIG_SERVER_PASSWORD:password}
retry:
initial-interval: 2000
max-interval: 10000
multiplier: 2
max-attempts: 10当使用 Spring Cloud 时,通常从服务器加载“real”配置数据。为了获取 URL(和其他连接配置,如密码等),您需要一个较早的或“bootstrap”配置。因此,您将配置服务器属性放在 bootstrap.yml 中,该属性用于加载实际配置数据(通常覆盖 application.yml [如果存在] 中的内容)。
当然,在一些情况上不用那么区分这两个文件,你只需要使用 application 文件即可,把全部选项都写在这里,效果基本是一致的,在不考虑上面的加载顺序覆盖的问题上。
总结
- bootstrap.yml 文件里面放系统级别的配置,基本不会发生改变
- 并且在使用 spring cloud 的时候,一定要把 config server 的属性配置到 bootstrap.yml 文件里面,因为 bootstrap.yml 加载顺序优先于 application.yml 文件,这样的话,就可以在 application.yml 加载之前加载远程的配置,然后去覆盖 application.yml (如果有)中的配置;然后 application.yml 配置文件中的配置就是应用的自动化配置了;
- 所以,如果项目中的配置比较多的时候建议 bootstrap.yml 和 application.yml 这两个配置文件一起使用最好;
- 如果项目中的配置比较少,就建议直接使用 application.yml 一个配置文件就够了;
YAML 编写规范
它的基本语法规则如下:
- 大小写敏感
- 使用缩进表示层级关系
- 缩进时不允许使用 Tab 键,只允许使用空格
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
规范一:编码规范
- 文档使用 Unicode 编码作为字符标准编码,例如 UTF-8
规范二:注释书写
使用“#”来表示注释内容
功能注释标在开头
语句注释标在 行后
1
2
3
4
5
6
7# 客户订单
date: 2015-02-01
customer:
name: Jai
items:
no: 1234 # 订单号
descript: cpu
规范三:缩进书写(2 个空格)
- 使用空格作为嵌套缩进工具。通常建议使用两个空格缩进,不建议使用 tab (甚至不支持)
规范四:序列表示
使用“-”(横线) + 单个空格表示单个列表项
1
2
3--- # 文档开始
- 第一章 简介
- 第二章 设计目录使用 “[]” 表示一组数据
1
2--- # 文档开始
[blue, red, green]组合表示。每个结构都可以嵌套组成复杂的表示结构。
1
2
3
4--- # 文档开始
- [blue, red, green] # 列表项本身也是一个列表
- [Age, Bag]
- site: { osc:www.oschina.net, baidu: www.baidu.com } # 这里是同 键值表 组合表示
规范五:键值表
使用 “:”(冒号) + 空格表示单个键值对
1
2
3
4
5
6
7
8# 客户订单
date: 2015-02-01
customer:
- name: Jai
items:
- no: 1234 # 订单号
- descript: cpu
- price: ¥800.00使用 “{}” 表示一个键值表
1
2
3
4
5# 客户订单
date: 2015-02-01
customer:
- name: Jai
items: { no: 1234, descript: cpu, price: ¥800.00 }“? “ 问号+空格表示复杂的键。当键是一个列表或键值表时,就需要使用本符号来标记。
1
2
3
4
5
6
7
8# 使用一个列表作为键
? [blue, reg, green]: Color
# 等价于
? - blue
- reg
- gree
: Color组合表示。每个结构都可以嵌套组成复杂的表示结构。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22Color:
- blue
- red
- green
# 相当于 (也是 JSON 的表示)
{Color: [blue, red, green]}
div:
- border: {color: red, width: 2px}
- background: {color: green}
- padding: [0, 10px, 0, 10px]
# 使用缩进表示的键值表与列表项
items:
- item: cpu
model: i3
price: ¥800.00
- item: HD
model: WD
price: ¥450.00
# 上面使用 “-” 前导与缩进来表示多个列表项,相当于下面的JSON表示
items: [{item:cpu, model:i3, price:¥800.00}, {item:HD, model:WD, price: ¥450.00}]
规范六:文本块
yaml: | 保留回车换行
使用 “|” 和文本内容缩进表示的块:保留块中已有的回车换行。相当于段落块
1
2yaml: | # 注意 ":" 与 "|" 之间的空格
JSON的语法其实是YAML的子集,大部分的JSON文件都可以被YAML的解释器解释。
yaml: > 回车变空格
使用 “>” 和文本内容缩进表示的块:将块中回车替换为空格,最终连接成一行。
1
2
3yaml: > # 注意 ":" 与 ">" 之间的空格,另外可以使用空行来分段落
JSON的语法其实是YAML的子集,
大部分的JSON文件都可以被YAML的解释器解释。
多行变一行
使用定#界符“”(双引号)、‘’(单引号)或回车表示的块:最终表示成一行。
1
2
3
4
5
6yaml: # 使用回车的多行,最终连接成一行。
JSON的语法其实是YAML的子集,
大部分的JSON文件都可以被YAML的解释器解释。
yaml: # 使用了双引号,双引号的好处是可以转义,即在里面可以使用特殊符号
"JSON的语法其实是YAML的子集,
大部分的JSON文件都可以被YAML的解释器解释。"
规范七:数据类型的约定
常用基本类型
对一些常用数据类型的表示格式进行了约定,包括:
1
2
3
4
5
6
7
8
9
10
11
12
13
14integer: 12345 # 整数标准形式
octal: 0o34 # 八进制表示,第二个是字母 o
hex: 0xFF # 十六进制表示
float: 1.23e+3 # 浮点数
fixed: 13.67 # 固定小数
minmin: -.inf # 表示负无穷
notNumber: .NaN # 无效数字
null: # 空值
boolean: [true, false] # 布尔值
string: "12345" # 字符串
date: 2015-08-23 # 日期
datetime: 2015-08-23T02:02:00.1z # 日期时间
iso8601: 2015-08-23t21:59:43.10-05:00 # iso8601 日期格式
spaced: 2015-08-23 21:59:43.10 -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
42isString: !!str 2015-08-23 # 强调是字符串不是日期数据
picture: !!binary | # Base64 图片
R0lGODlhDAAMAIQAAP//9/X
17unp5WZmZgAAAOfn515eXv
Pz7Y6OjuDg4J+fn5OTk6enp
56enmleECcgggoBADs=
#下面是内置类型
!!int # 整数类型
!!float # 浮点类型
!!bool # 布尔类型
!!str # 字符串类型
!!binary # 也是字符串类型
!!timestamp # 日期时间类型
!!null # 空值
!!set # 集合
!!omap, !!pairs # 键值列表或对象列表
!!seq # 序列,也是列表
!!map # 键值表
#下面是一些例子:
--- !!omap
- Mark: 65
- Sammy: 63
- Key: 58
--- !!set # 注意,“?”表示键为列表,在这里列表为 null
? Mark
? Sammy
? Key
# 下面是自定义的类型或标识
%TAG ! tag:clarkevans.com,2002: # % 是指令符号
--- !shape
# Use the ! handle for presenting
# tag:clarkevans.com,2002:circle
- !circle
center: &ORIGIN {x: 73, y: 129}
radius: 7
- !line
start:
finish: { x: 89, y: 102 }
- !label
start:
color: 0xFFEEBB
text: Pretty vector drawing.
规范八:锚点与引用,定义数据的复用
第一步:使用 “&” 定义数据锚点(即要复制的数据)
第二步:使用 “*” 引用上述锚点数据(即数据的复制目的地)
1
2
3
4
5
6
7
8
hr:
- Mark McGwire
# Following node labeled SS
- &SS Sammy Sosa # 定义要复制的数据
rbi:
- *SS # Subsequent occurrence 这里是数据复制目标
- Ken Griffey
说明
- SpringBoot 的学习内容来自 B 站 SpringBoot 最新教程 IDEA 版,文章内容根据视频学习进行的记录。