🤖🤖-摘要:
本文介绍了SpringBoot的核心特性,包括SpringApplication的使用,如何通过配置文件和代码进行自定义设置,以及启动失败时的处理方式。文中还详述了如何实现配置文件的隔离和外置,解释了属性占位符的用途,以及配置的优先级顺序。最后,介绍了日志的使用和JUnit5单元测试。

官方文档:

Spring Application: SpringApplication
External Configuration: External Configuration
Profiles: Profiles
Logging: Logging

SpringApplication

SpringApplication简化了Spring程序的启动过程.
大多数情况下, 可以委托给静态SpringApplication.run方法, 如以下示例所示:

@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}

启动日志:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.0)

2023-07-05T14:07:10.668+08:00 INFO 9584 --- [ main] com.fredo.Main : Starting Main using Java 17.0.2 with PID 9584 (D:\Develop\Projects\ideaProject\spring-tutorial\spring-boot\demo05-features\target\classes started by Administrator in D:\Develop\Projects\ideaProject\spring-tutorial)
2023-07-05T14:07:10.673+08:00 INFO 9584 --- [ main] com.fredo.Main : No active profile set, falling back to 1 default profile: "default"
2023-07-05T14:07:12.122+08:00 INFO 9584 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-07-05T14:07:12.123+08:00 INFO 9584 --- [ main] o.a.catalina.core.AprLifecycleListener : An older version [1.2.34] of the Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of [2.0.1]
2023-07-05T14:07:12.123+08:00 INFO 9584 --- [ main] o.a.catalina.core.AprLifecycleListener : Loaded Apache Tomcat Native library [1.2.34] using APR version [1.7.0].
2023-07-05T14:07:12.140+08:00 INFO 9584 --- [ main] o.a.catalina.core.AprLifecycleListener : OpenSSL successfully initialized [OpenSSL 1.1.1o 3 May 2022]
2023-07-05T14:07:12.159+08:00 INFO 9584 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-07-05T14:07:12.159+08:00 INFO 9584 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.8]
2023-07-05T14:07:12.356+08:00 INFO 9584 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-07-05T14:07:12.360+08:00 INFO 9584 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1596 ms
2023-07-05T14:07:13.208+08:00 INFO 9584 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-07-05T14:07:13.219+08:00 INFO 9584 --- [ main] com.fredo.Main : Started Main in 3.223 seconds (process running for 4.118)

注意: 只有前两行和最后一行是SpringBoot的启动日志
启动日志可以关闭:

  • 配置文件
spring.main.log-startup-info=false
  • 代码:
SpringApplication application=new SpringApplication(Main.class);

// 关闭启动日志(注意:配置文件的优先级大于代码优先级!!!)
application.setLogStartupInfo(false);
application.run(args);

启动失败

如果应用程序无法启动, 已注册的FailureAnalyzers将有机会提供专用的错误消息和解决问题的具体操作
以端口占用为例:

***************************
APPLICATION FAILED TO START
***************************

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that is listening on port 8080 or configure this application to listen on another port.

FailureAnalyzers是一个用于分析应用程序失败原因的工具.当应用程序发生失败时,FailureAnalyzers会收集失败信息,
并分析失败原因,以便开发人员能够更好地理解应用程序的健康状况.

可自定义:

  • 1.自定义类继承AbstractFailureAnalyzer,并重写analyze方法.可参考:BindValidationFailureAnalyzer
  • 2.注册在META-INF/spring.factories 文件中
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.fredo.custom.MyFailureAnalyzer

延迟初始化

在容器启动时不初始化Bean,只有在第一次使用时再初始化

配置方法:

  • 配置文件
spring.main.lazy-initialization=true
  • 代码:
// 开启延迟初始化(默认关闭,不建议开启)
application.setLazyInitialization(true);

可以使用注解@Lazy(false), 单独指定某些Bean延迟初始化

自定义Banner

Banner 就是程序启动时最上面的信息

类路径添加文件:banner.txt或设置spring.banner.location就可以定制 Banner
推荐网址

关闭

  • 配置文件
spring.main.banner-mode=off
  • 代码:
// 关闭Banner,默认值:CONSOLE
application.setBannerMode(Banner.Mode.OFF);

自定义SpringApplication

public static void main(String[]args){
SpringApplication application=new SpringApplication(Main.class);

// 关闭启动日志(注意:配置文件的优先级大于代码优先级!!!)
application.setLogStartupInfo(false);

// 开启延迟初始化(默认关闭,不建议开启)
application.setLazyInitialization(true);

// 关闭Banner,默认值:CONSOLE
// application.setBannerMode(Banner.Mode.OFF);

application.run(args);
}

自定义信息在application.properties中,
具体可参考官网

流式构造API

可用于构建父子层次结构

public static void main(String[]args){
new SpringApplicationBuilder()
.sources(Main.class) // 父
.child(Main.class) // 子,非必须
.bannerMode(Banner.Mode.OFF)
.run(args);
}

配置文件隔离

环境隔离: 快速切换开发、测试、生产环境
步骤:

  1. 标识环境:指定哪些组件、配置在哪个环境生效
  2. 切换环境:这个环境对应的所有组件和配置就应该生效

指定环境

Spring Profiles 提供一种隔离配置的方式, 使其仅在特定环境生效
任何组件都可用@Profile标记, 来指定何时被加载

例如:

  • dev环境: @Profile({“dev”})
  • dev和prod环境: @Profile({“dev”, “prod”})

激活环境

配置文件激活

spring.profiles.active=prod

命令行激活

java -jar xxx.jar --spring.profiles.active=prod

注意:

  • 不标注@Profile的组件无论是在哪个环境中都会激活
  • 存在默认环境@Profile({"default"}),需要激活默认环境才有效
  • 也可以设置默认激活的环境, spring.profiles.default=dev
  • 推荐使用激活方式激活指定环境

环境包含

在配置文件(必须是在主配置文件中)中设置:

spring.profiles.include[0]=dev
spring.profiles.include[1]=test
或者:
spring.profiles.include=dev,test

最佳实践

生效的环境 = 激活的环境/默认环境 + 包含的环境

项目中:

  • 基础的配置mybatis,log,…:写到包含环境
  • 要动态切换变化的db, redis,…:写到激活的环境

Profile 分组

创建prod组,指定包含db和mq配置

spring.profiles.group.prod[0]=db
spring.profiles.group.prod[1]=mq

使用--spring.profiles.active=prod, 就会激活prod, 就会使用db, mq配置文件

Profile 配置文件

  • application-{profile}.properties可以作为指定环境的配置文件
  • 激活这个环境,配置就会生效。最终生效的所有配置是
    • application.properties:主配置文件,任意时候都生效
    • application-{profile}.properties:指定环境配置文件,激活指定环境生效

profile优先级 > application

外置配置文件

场景:线上应用如何快速修改配置,并应用最新配置?

  • SpringBoot 使用 配置优先级 + 外部配置 简化配置更新、简化运维。
  • 只需要给jar应用所在的文件夹放一个application.properties最新配置文件,重启项目就能自动应用最新配置

SpringBoot允许将配置外部化, 以便可以在不同的环境中使用相同的应用程序代码.
我们可以使用各种外部配置源, 包括Java Properties文件YAML文件环境变量命令行参数

@Value可以获取值, 也可以用@ConfigurationProperties将所有属性绑定到java object中

配置优先级

以下是SpringBoot属性源加载顺序。由低到高,高优先级配置覆盖低优先级

  1. 默认属性(通过SpringApplication.setDefaultProperties指定的)
  2. @PropertySource指定加载的配置(需要写在@Configuration类上才可生效)
  3. 配置文件(application.properties/yml等)
  4. RandomValuePropertySource支持的random.*配置(如:@Value("${random.int}")
  5. OS 环境变量
  6. Java 系统属性(System.getProperties())
  7. JNDI 属性(来自java:comp/env)
  8. ServletContext 初始化参数
  9. ServletConfig 初始化参数
  10. SPRING_APPLICATION_JSON属性(内置在环境变量或系统属性中的 JSON)
  11. 命令行参数
  12. 测试属性。(@SpringBootTest进行测试时指定的属性)
  13. 测试类@TestPropertySource注解
  14. Devtools 设置的全局属性。($HOME/.config/spring-boot)

小结一下:
常见的优先级顺序:
命令行> 配置文件> springapplication配置

配置文件优先级如下:(后面覆盖前面)

  1. jar 包内的application.properties/yml
  2. jar 包内的application-{profile}.properties/yml
  3. jar 包外的application.properties/yml
  4. jar 包外的application-{profile}.properties/yml

建议:用一种格式的配置文件。如果.properties和.yml同时存在,则.properties优先

小结一下:

  • 包外 > 包内
  • 同级情况:profile配置 > application配置

所有参数均可由命令行传入,使用--参数项=参数值,将会被添加到环境变量中,并优先于配置文件
比如java -jar app.jar --name="Spring",可以使用@Value("${name}")获取

演示场景:

  • 包内: application.properties server.port=8000
  • 包内: application-dev.properties server.port=9000
  • 包外: application.properties server.port=8001
  • 包外: application-dev.properties server.port=9001

启动端口: 命令行 > 9001 > 8001 > 9000 > 8000

外部配置

SpringBoot 应用启动时会自动寻找application.propertiesapplication.yaml位置进行加载.
顺序如下:(后面覆盖前面)

  • 类路径: 内部
    • 类根路径
    • 类下/config
  • 当前路径(项目所在的位置)
    • 当前路径
    • 当前下/config子目录
    • /config目录的直接子目录

最终效果:优先级由高到低,前面覆盖后面

  • 命令行 > 包外config直接子目录 > 包外config目录 > 包外根目录 > 包内目录
  • 同级比较:
    • profile配置 > 默认配置
    • properties配置 > yaml配置
配置优先级

规律:最外层的最优先

  • 命令行 > 所有
  • 包外 > 包内
  • config目录 > 根目录
  • profile > application

配置不同就都生效(互补),配置相同高优先级覆盖低优先级

导入配置

使用spring.config.import可以导入额外配置

spring.config.import=my.properties
my.property=value

无论以上写法的先后顺序, my.properties的值总是优先于直接在文件中编写的my.property

属性占位符

配置文件中可以使用${name:default}形式取出之前配置过的值

app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}

日志

详细可参考SpringBoot日志

单元测试-JUnit5

详细可参考SpringBoot单元测试