最近在学习了 Spring Boot 后,也用它写了一个简单的项目,真的发现它对使用 Spring 开发的人来说是一大福音,无需在像以前那样需要配置很多东西。这篇文章,就结合一些常见的面试题和开发中会用到的,对 Spring Boot 来总结一下。
一、Spring Boot 是什么
Spring Boot,看这个名字,就可以猜出来它是一个快速启动 Spring 的框架,其实也正是如此,它采用“约定大于配置”的理念,提供了大量的自动配置,而无须再去编写模板化的配置文件,可以快速地创建一个可以独立运行的 Spring 项目。
除了自动配置特性之外,它还有以下特性:
starter 启动器
它提供了很多框架的 starter 启动器,来简化 maven 的依赖管理。Spring 项目中,在导入其他框架的依赖时,还需要导入其他附属的依赖,如果框架比较多,那就会比较难以管理。而 Spring Boot 中提供了各种 starter 启动器,可以对其进行很好的管理。例如,导入 spring-boot-starter-web 依赖后,会自动添加如下依赖:
内嵌 Servlet 容器
它内嵌了很多 Servlet 容器,可以选择 Tomcat、Jetty 等。这样就无须先下载 Tomcat,搭建好运行环境,再以 war 包的形式进行部署,而是可以直接以 jar 包的形式,通过 java -jar xxx.jar 去独立运行。
准生产环境的应用监控
提供了准生产环境的应用监控。可以基于 HTTP、JMX、SSH 等对运行时的项目进行监控。对 Actuator 还不太了解,后续再进行补充。
二、Spring、SpringBoot、SpringCloud
很多人应该都听说过这三个东西,那它们之间到底有什么区别呢?
学过 Spring 的应该都知道这样一句话,Spring 是一个 JavaSE/EE 一站式的轻量级开源框架。其中提供了很多模块,例如 IoC、AOP、MVC、Test 等。SpringMVC 只是其中的一个模块。
而 SpringBoot 是基于 Spring 的一个 Boot 启动器,为了更容易、更快速地搭建一个 Spring 项目。针对的是单体应用。
SpringCloud 则是微服务架构下的一个综合性解决方案,对使用 SpringBoot 开发的一个个服务进行管理,它整合了许多基础组件,来解决业务拆分后带来的如配置管理、服务治理、容错等问题。
三、Spring Boot 的启动方式
Spring Boot 的启动方式主要有三种,下面就分别来看一下:
1. 打成 jar 包
前面说了 Spring Boot 中内置了 Serlvet 容器,可以直接使用 java -jar xxx.jar。目前也推荐使用这种方式。另外通过这种方式,也可以在运行时指定一些参数。
在 pom.xml 文件中,引入 spring-boot-maven-plugin 插件后:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
可以执行 mvn clean package 命令,将其打包成一个 jar 包,然后就可以通过 jar -jar xxx.jar 命令运行。
2. 运行 main 方法
在 Spring Boot 项目都会有一个主类,可以通过运行该类的 main 方法来启动。这比较适用于开发调试的时候。
3. 打成 war 包
如果是 web 项目,也可以打成 war 包,然后使用外部的 Tomcat 容器。
四、配置文件
虽然 Spring Boot 提供了一系列自动化配置,来简化繁重的配置。但是我们也要了解如何来修改这些默认配置,来适应一些特殊需求的场景。
4.1 配置方式
目前 Spring Boot 支持两种配置方式,一种是传统的 properties 文件,以 key=value 形式来表示。例如,要修改默认的端口:
server.port=8081
另一种是目前比较推荐使用的 YAML 文件。它是以缩进的形式来表示,其结构更加地清晰易读。例如:
server:
port: 8081
另外,YAML 文件也支持在同一个文件中通过 spring.profiles 属性来定义多个不同的环境的配置。例如,在下面的文件中:
server:
port: 8080
---
server:
port: 8081
spring:
profiles: prod
---
server:
port: 8082
spring:
profiles: test
如果我们指定为 test 环境,server.port 就使用 8082 端口;如果指定为 prod 环境,就使用 8081 端口,否则没有指定的话,就使用 8080 端口。
但是 YAML 文件有一些不足,它不能通过 @PropertySource 注解来加载指定的 YAML 配置文件。不过可以通过 @Value 注解。
更多关于 YAML 的详细语法,可以参考:阮一峰:YAML 语言教程
4.2 配置读取方式
对于自定义的配置,要应用到我们的项目当中,SpringBoot 目前支持两种读取方式。它们也都支持和 @PropertySource 配合,来指定使用的配置文件。
1. @Value
一种是刚才提到的 @Value,读取配置到具体的属性上。
例如,在 application.yml 文件中添加如下配置:
user:
name: TimberLiu
age: 21
address: China
在 User 类就可以按照如下的方式进行读取:
@Component
@Setter
@Getter
public class User {
@Value("${user.name}")
public String name;
@Value("${user.age}")
public int age;
@Value("${user.address}")
public String address;
}
2. @ConfigurationProperties
另外一种是 @ConfigurationProperties,读取配置到类上。
同样是上面的配置内容,使用 @ConfigurationProperties 就可以像如下这样配置:
@Component
@Setter
@Getter
@ConfigurationProperites(prefix="user")
public class User {
public String name;
public Integer age;
public String address;
}
3. 两者的区别
那这两种方式有什么区别呢?通过下面这个表格来看一下:
| / | @ConfigurationProperties | @Value |
|---|---|---|
| 功能 | 读取配置到类上 | 读取配置到属性上 |
| 松散绑定 | 支持 | 不支持 |
| JSR303 数据校验 | 支持 | 不支持 |
| 复杂类型封装 | 支持 | 不支持 |
下面通过一个例子来说明,例如对于下面的配置内容:
person:
name: timberliu
age: 21
birthday: 2019/4/17
info: {k1: v1,k2: v2}
lists:
- jack
- rose
dog:
last_name: wang # 属性中的名,last_name 匹配 lastName,松散绑定
age: 3
使用 @ConfigurationProperties 可以如下配置:
@Component
@Getter
@Setter
@ConfigurationProperties("person")
@Validated
public class Person {
// 非空校验
@NotNull
private String name;
private Integer age;
// 日期类型,数据校验
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private Date birthday;
// 复杂类型
private Map<String, String> info;
private List<Object> lists;
private Dog dog;
}
@Component
@Getter
@Setter
@ConfigurationProperties("person.dog")
public class Dog {
private String lastName;
private Integer age;
}
4.3 多环境配置
一般来说,项目都会对于不同的环境使用不同的配置,在 Spring Boot 中,多环境配置的文件名需要满足 application-{profile}.properties 或者 .yml 的格式,其中 profile 对应的环境标识。
至于具体哪个环境会被加载,需要在 application.properties 文件中通过 spring.profiles.active 属性进行设置。
例如,如果有三个环境的配置文件:
application-dev.properties
application-test.properties
application-prod.properties
在 application.properties 文件中指定 spring.profiles.active=dev,就会加载 application-dev.properties 配置文件中的内容。
一般在实际开发中,多环境的配置思路如下:
- 在
application.properties文件中配置一些通用的属性,并设置spring.profiles.active=dev,默认配置为开发环境。 - 在
application-{profile}.properties文件中去配置不同环境不同的内容。 - 具体什么环境,通过命令行的方式去激活对应环境的配置。
4.4 配置加载顺序
通过前面已经了解到,属性可以在很多地方进行配置,例如 application.properties 或者 application-{profile}.properties 文件中,命令行中等等。那么为了能够更合理地重写各属性的值,下面来看一下这些配置的加载顺序是怎样的。由于这里加载顺序非常多,这里只列举一些常用的:
- 命令行指定的参数。例如
java -jar myapplication.jar --server.port=8081。 Java系统变量。- 通过
random.*配置的随机属性。 Jar包外部的,针对不同{profile}环境的配置文件内容,例如application-{profile}.properties。Jar包内部的,针对不同{profile}环境的配置文件内容,例如application-{profile}.yml。Jar包外部的application.properties或application.yml。Jar包内部的application.properties或application.yml。- 在自定义的
@Configuration类中,通过@PropetySource注解定义的属性。 - 使用
SpringApplication.setDefaultProperties定义的属性。
这些加载顺序,越往下优先级越低。
五、最后
本文介绍了 Spring Boot 的基本概念。其中详细说了 SpringBoot 的配置文件,例如配置文件的格式、读取方式,多环境下应该如何配置,及配置文件的加载顺序。
下篇文章将详细说一下 SpringBoot 的启动方式和自动配置原理。