如此简单的 SpringBoot,不了解一下

1,566 阅读7分钟

最近在学习了 Spring Boot 后,也用它写了一个简单的项目,真的发现它对使用 Spring 开发的人来说是一大福音,无需在像以前那样需要配置很多东西。这篇文章,就结合一些常见的面试题和开发中会用到的,对 Spring Boot 来总结一下。

一、Spring Boot 是什么

Spring Boot,看这个名字,就可以猜出来它是一个快速启动 Spring 的框架,其实也正是如此,它采用“约定大于配置”的理念,提供了大量的自动配置,而无须再去编写模板化的配置文件,可以快速地创建一个可以独立运行的 Spring 项目。

除了自动配置特性之外,它还有以下特性:

starter 启动器

它提供了很多框架的 starter 启动器,来简化 maven 的依赖管理。Spring 项目中,在导入其他框架的依赖时,还需要导入其他附属的依赖,如果框架比较多,那就会比较难以管理。而 Spring Boot 中提供了各种 starter 启动器,可以对其进行很好的管理。例如,导入 spring-boot-starter-web 依赖后,会自动添加如下依赖:

内嵌 Servlet 容器

它内嵌了很多 Servlet 容器,可以选择 TomcatJetty 等。这样就无须先下载 Tomcat,搭建好运行环境,再以 war 包的形式进行部署,而是可以直接以 jar 包的形式,通过 java -jar xxx.jar 去独立运行。

准生产环境的应用监控

提供了准生产环境的应用监控。可以基于 HTTPJMXSSH 等对运行时的项目进行监控。对 Actuator 还不太了解,后续再进行补充。

二、Spring、SpringBoot、SpringCloud

很多人应该都听说过这三个东西,那它们之间到底有什么区别呢?

学过 Spring 的应该都知道这样一句话,Spring 是一个 JavaSE/EE 一站式的轻量级开源框架。其中提供了很多模块,例如 IoCAOPMVCTest 等。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.propertiesapplication.yml
  • Jar部的 application.propertiesapplication.yml
  • 在自定义的 @Configuration 类中,通过 @PropetySource 注解定义的属性。
  • 使用 SpringApplication.setDefaultProperties 定义的属性。

这些加载顺序,越往下优先级越低。

五、最后

本文介绍了 Spring Boot 的基本概念。其中详细说了 SpringBoot 的配置文件,例如配置文件的格式、读取方式,多环境下应该如何配置,及配置文件的加载顺序。

下篇文章将详细说一下 SpringBoot 的启动方式和自动配置原理。