SpringBoot是Spring项目的一个子工程,它将一些主流的技术与Spring框架进行了整合,基于约定优于配置的思想,为开发者提供了一个方便快捷的工程脚手架。
简化依赖管理:对于常见的业务场景,通过启动器(Starter)对所需依赖进行搭配和版本管理,开发者只需要引入场景启动器即可。
进行默认配置:分析导入的依赖,通过条件注解(@Condition)对业务场景进行默认配置,减少了项目中的"模板化"配置。
加载外部属性:从命令行参数、系统环境变量、外部属性文件等位置加载外部属性,并通过Environment进行统一管理。
提供运行监控:监控程序运行状况,通过端点的方式提供程序健康状态、安全指标、属性配置等监控信息。
内嵌servlet容器:通过Maven插件直接将程序打包为可执行的Jar包文件,无需应用服务器即可独立运行。
注意:
由于SpringBoot需要基于模块装配+条件装配+SPI机制等实现“约定大于配置”的思想,因此一般采用注解配置的方式。
基于XML的配置方式编写更灵活、易修改(无需重新打包),但是不方便整合场景制作启动器(需要根据不同的情况进行注册)。
SpringBoot为我们提供了非常快速的开发体验,通过下面几个步骤,将会搭建一个简单的Web应用程序。
新建一个Maven项目,在pom.xml
文件中继承SpringBoot父工程:spring-boot-starter-parent
。
x1
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>org.example</groupId>
8 <artifactId>SpringBoot-demo</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <!-- 继承SpringBoot父工程:spring-boot-starter-parent -->
12 <parent>
13 <groupId>org.springframework.boot</groupId>
14 <artifactId>spring-boot-starter-parent</artifactId>
15 <version>2.1.1.RELEASE</version>
16 </parent>
17
18</project>
注意:下面是本文档所使用的SpringBoot 2.1.1.RELEASE版本相关信息,请关注你所使用的SpringBoot版本!
基础依赖版本:Java8+(兼容Java11)、Spring Framework 5.1.3.RELEASE+、Maven3.3+。
内置容器版本:Tomcat 9.0(Servlet Version 4.0)。
我们开发的是一个Web应用,则在pom.xml文件中引入Web应用场景的启动器:spring-boot-starter-web
。
71<dependencies>
2 <dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-web</artifactId>
5 </dependency>
6</dependencies>
7
SpringBoot应用一般需要一个启动类来进行引导程序的启动和开启自动配置。
121package com.huangyuanxin.notes.springboot;
2
3import org.springframework.boot.SpringApplication;
4import org.springframework.boot.autoconfigure.SpringBootApplication;
5
6
7public class MyApplication {
8 public static void main(String[] args) {
9 SpringApplication.run(MyApplication.class, args);
10 }
11}
12
编写一个简单的/hello
接口,来测试下我们的SpringBoot应用。
131package com.huangyuanxin.notes.springboot.controller;
2
3import org.springframework.web.bind.annotation.GetMapping;
4import org.springframework.web.bind.annotation.RestController;
5
6
7public class HelloController {
8 "hello") (
9 public String hello() {
10 return "hello,SpringBoot!";
11 }
12}
13
直接在IDEA中执行main函数
,或者在工程根目录(pom.xml文件所在目录)通过mvn spring-boot:run
命令启动。
当启动完成后,点击http://localhost:8080/hello即可进行访问!
由于Java没有提供加载嵌套jar文件的标准方法,因此,需要引入一个插件spring-boot-maven-plugin
来支持它。
91<build>
2 <plugins>
3 <plugin>
4 <groupId>org.springframework.boot</groupId>
5 <artifactId>spring-boot-maven-plugin</artifactId>
6 </plugin>
7 </plugins>
8</build>
9
然后,在工程根目录(pom.xml文件所在目录)使用mvn package -Dmaven.test.skip=true
命令来对其进行打包。
打包完成后会生成SpringBoot-demo-1.1-SNAPSHOT.jar.original
和SpringBoot-demo-1.1-SNAPSHOT.jar
两个文件。前者为Maven生成的原始Jar文件,仅包含当前工程代码,一般提供给其它工程引用;后者为SpringBoot重新打包后生成的可执行jar文件,额外包含了工程的所有依赖Jar包及启动代码。
最后,使用java -jar SpringBoot-demo-1.0-SNAPSHOT.jar
命令来启动和测试它!
提示:如果需要支持远程调试,请使用如下命令启动你的SpringBoot应用程序:
21java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n
2-jar SpringBoot-demo-1.0-SNAPSHOT.jar
一般来说,SpringBoot项目都会继承spring-boot-starter-parent
作为父工程,它提供了版本管理和默认配置:
版本管理:通过dependencyManagement标签对常见依赖进行版本管理,这些依赖会随SpringBoot一起升级。
默认配置:提供了一些默认属性和插件配置,如默认的源码编译级别(1.8)、默认的字符编码(UTF-8)、使用-parameters编译等。
除此之外,SpringBoot父工程还会进行一些插件的默认配置以及对配置文件(application.properties)的进行敏感资源过滤等。
父工程中的默认属性,可以通过覆盖的方式修改它们,如下例所示:
51<properties>
2 <!--通过属性修改spring-data的默认版本为Fowler-SR2-->
3 <spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
4</properties>
5
如果不想继承父工程,则也可以通过如下方式来使用SpringBoot的版本管理功能,但是你不能使用覆盖的方式去修改默认属性。
121<dependencyManagement>
2 <dependencies>
3 <dependency>
4 <!-- Import dependency management from Spring Boot -->
5 <groupId>org.springframework.boot</groupId>
6 <artifactId>spring-boot-dependencies</artifactId>
7 <version>2.1.1.RELEASE</version>
8 <type>pom</type>
9 <scope>import</scope>
10 </dependency>
11 </dependencies>
12</dependencyManagement>
场景启动器(Starter)是SpringBoot管理复杂依赖关系的一种手段,你可以把它理解为一些用于某项功能所需要依赖的集合。SpringBoot官方为一些应用场景内置相应的启动器,一般以spring-boot-starter-
开头,下面是常见的启动器列表:
Name | Description | Pom |
---|---|---|
spring-boot-starter | 核心启动器,包括自动配置、日志记录和YAML格式支持等 | Pom |
spring-boot-starter-actuator | 提供生产就绪功能,帮助您监视和管理应用程序 | Pom |
spring-boot-starter-aop | 使用SpringAOP和AspectJ进行面向切面编程 | Pom |
spring-boot-starter-jdbc | 使用JDBC访问数据库(使用HikariCP连接池) | Pom |
spring-boot-starter-test | 集成了JUnit、Hamcrest、Mockito等一些测试依赖 | Pom |
spring-boot-starter-web | 构建基于SpringMVC的Web应用程序(默认嵌入tomcat容器) | Pom |
spring-boot-starter-log4j2 | 使用Log4j2进行日志记录 | Pom |
spring-boot-starter-logging | 使用Logback进行日志记录(默认的日志启动器) | Pom |
spring-boot-starter-tomcat | 使用Tomcat作为嵌入式servlet容器 | Pom |
除上述一些官方内置的启动器外,第三方项目也可以基于开放的接口定义自己的启动器,如MyBatis定义的mybatis-spring-boot-starter
启动器等。更多第三方启动器,可参考GitHub上spring-boot-starters模块中的README file。
@SpringBootApplication注解用于标识该应用为一个SpringBoot应用程序,它由如下三个注解组成:
@EnableAutoConfiguration:开启SpringBoot的自动配置(该注解只能被添加一次)。
@SpringBootConfiguration:声明当前类是一个配置类,本质是@Configuration注解的包装类。
@ComponentScan:配置注解扫描,等同于<context:component-scan />,默认扫描当前包及其子包。
提示:如果需要注册不在扫描路径内的Spring组件,可以使用Spring的
@Import
或@ImportResource
注解。
如果想禁用某个自动配置,可以使用该注解的exclude
属性,如以下示例所示:
71exclude={DataSourceAutoConfiguration.class}) (
2public class MyApplication {
3 public static void main(String[] args) {
4 SpringApplication.run(MyApplication.class, args);
5 }
6}
7
如果该类不在CLASSPATH中,则可以使用相关的excludeName
属性,并指定全限定类名。除此之外,您也可以在application.yml中使用spring.autoconfigure.exclude
属性来控制要排除的自动配置类的列表。
SpringApplication类提供了一个静态方法run,可以方便的从main函数来启动Spring应用程序,如下例所示。
51public static void main(String[] args) {
2 // 创建并引导启动Spring应用程序(第一个参数为@Configuration配置对象,第二个参数为main函数参数)
3 SpringApplication.run(MyApplication.class, args);
4}
5
当然,你也可以创建一个本地实例,并对其进行自定义设置后再启动。
51public static void main(String[] args) {
2 SpringApplication app = new SpringApplication(MyApplication.class);
3 app.setBannerMode(Banner.Mode.OFF);
4 app.run(args);
5}
如果你更喜欢流式编程(Fluent Builder API),也可以使用如下方式。
61public static void main(String[] args) {
2 new SpringApplicationBuilder()
3 .sources(MyApplication.class)
4 .bannerMode(Banner.Mode.OFF)
5 .run(args);
6}
此外,利用 SpringapplicationBuilder 可以构建具有层次关系的 Spring Boot 应用程序:
11new springapplicationBuilder(...).parent(...).child(...).run(...);
入门案例中已经讲解了如何启动SpringBoot应用程序。
在META-INF/spring.factories
文件中添加如下配置后,就可以生成相应的PID和PORT文件,默认的文件名为application.port
和application.port
。
41org.springframework.context.ApplicationListener=\
2org.springframework.boot.context.ApplicationPidFileWriter,\
3org.springframework.boot.web.context.WebServerPortFileWriter
4
如需修改默认生成的文件名,可以使用spring.pid.file=/var/log/app.pid
属性,或采用编程方式进行配置。
如果程序启动失败,SpringBoot会通过已注册的FailureAnalyzer
来分析错误,以提供专用的错误消息和解决该问题的具体措施。如端口被占用时会打印如下错误报告。
121***************************
2APPLICATION FAILED TO START
3***************************
4
5Description:
6
7The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured.
8
9Action:
10
11Verify the connector's configuration, identify and stop any process that's listening on port 8080, or configure this application to listen on another port.
12
如果需要进行扩展,可继承针对于特定异常类型的AbstractFailureAnalyzer<T extends Throwable>
抽象类,并在META-INF/spring.factories
中通过如下配置进行注册。
21org.springframework.boot.diagnostics.FailureAnalyzer=com.example.ProjectConstraintViolationFailureAnalyzer
2
提示:
使用JSR-303注解出现异常时也会由FailureAnalyzer来分析错误。
在FailureAnalyzer中,可以通过实现BeanFactoryAware和EnvironmentAware接口来获取BeanFactory和Environment。
SpringApplication可以在创建时通过其JavaAPI或spring.main
前缀的外部化属性进行自定义设置。
91# 设置sources属性(注意:该属性做了特殊处理,不会被覆盖,而是合并)
2spring.main.sources=com.acme.Config,com.acme.ExtraConfig
3
4# 开启Banner打印
5spring.main.banner-mode=console
6
7# 移除嵌入式Web服务器
8spring.main.web-application-type=none
9
SpringBoot应用在启动时会自动加载类路径下的banner.txt
文件或同名.gif/.jpg/.png
结尾的图片(转化为ASCII艺术作品)来打印Banner。banner.txt文件示例如下:
111
2${AnsiColor.RED} ██████╗ ${AnsiColor.BLUE}██╗ ██╗
3${AnsiColor.RED}██╔═══██╗${AnsiColor.BLUE}██║ ██╔╝
4${AnsiColor.RED}██║ ██║${AnsiColor.BLUE}█████╔╝
5${AnsiColor.RED}██║ ██║${AnsiColor.BLUE}██╔═██╗
6${AnsiColor.RED}╚██████╔╝${AnsiColor.BLUE}██║ ██╗
7${AnsiColor.RED} ╚═════╝ ${AnsiColor.BLUE}╚═╝ ╚═╝
8
9${AnsiColor.BRIGHT_BLUE}:: Running Spring Boot ${spring-boot.version} ::
10:: http://notes.huangyuanxin.com ::${AnsiColor.DEFAULT}
11
在banner.txt中,可以使用下面一些占位符:
占位符 | 描述 | 示例 |
---|---|---|
${application.version} | MANIFEST.MF文件中声明的应用程序的版本号(Implementation-Version: 1.0) | 1.0 |
${application.formatted-version} | MANIFEST.MF文件中声明的应用程序的版本号(格式化) | (v1.0) |
${spring-boot.version} | 您正在使用的 Spring Boot 版本 | 2.1.1.RELEASE |
${spring-boot.formatted-version} | 您正在使用的 Spring Boot 版本(格式化) | (v2.1.1.RELEASE) |
${Ansi.Xxx} ${AnsiColor.Xxx} ${AnsiBackground.Xxx} ${AnsiStyle.Xxx}) | 其中Xxx是 ANSI 转义代码的名称。有关详情,请参见AnsiPropertySource | AnsiColor.GREEN AnsiBackground.RED AnsiStyle.BOLD |
${application.title} | MANIFEST.MF文件中声明的应用程序标题(Implementation-Title: MyApp)。 | MyApp |
以及下面一些属性来进行相关配置:
属性 | 作用 |
---|---|
spring.banner.location | 指定一个文本文件作为banner |
spring.banner.charset | 指定banner文件的字符集,默认为UTF-8。 |
spring.banner.image.location | 指定一张gif/jpg/png格式的图片作为banner,图片将转化为ASCII艺术作品展示 |
spring.main.banner-mode | 指定banner打印在控制台(console)还是日志(log),或者干脆不打印("off") |
除上述属性配置的方式外,也可以通过实现接口的方式来设置Banner。首先实现org.springframework.boot.Banner
接口。
191import org.springframework.boot.Banner;
2import org.springframework.core.env.Environment;
3import java.io.PrintStream;
4
5public class MyBanner implements Banner {
6 private static final String BANNER =
7 " ___ ___ .__ .__ \n" +
8 " / | \\ ____ | | | | ____ \n" +
9 "/ ~ \\_/ __ \\| | | | / _ \\ \n" +
10 "\\ Y /\\ ___/| |_| |_( <_> )\n" +
11 " \\___|_ / \\___ >____/____/\\____/ \n" +
12 " \\/ \\/ ";
13
14
15 public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
16 out.println(BANNER);
17 out.println();
18 }
19}
然后在启动应用前通过SpringApplication.setBanner(…)方法进行设置。
91public static void main(String[] args) {
2 SpringApplication springApplication = new SpringApplication(DemoApplication.class);
3 // 开打印Banner到日志(默认打印到控制台)
4 app.setBannerMode(Banner.Mode.LOG);
5 // 设置自定义Banner
6 springApplication.setBanner(new MyBanner());
7 // 启动Spring Boot
8 springApplication.run(args);
9}
提示:该实现类会被注册为名称叫springBootBanner的单例Bean。
SpringApplication根据当前依赖环境来为你创建合适的ApplicationContext
实现。
如果存在SpringMVC,则优先创建AnnotationConfigServletWebServerApplicationContext;
如果不存在SpringMVC且存在Spring WebFlux,则创建AnnotationConfigReactiveWebServerApplicationContext;
否则创建AnnotationConfigApplicationContext。
如果需要修改,你可以通过setWebApplicationType(WebApplicationType.Xxx)
轻松覆盖它!
WebApplicationType | 用途 |
---|---|
SERVLET | 指定为SpringMVC环境 |
REACTIVE | 指定为Spring WebFlux环境 |
NONE | 指定为Junit测试环境 |
提示:你也可以使用
spring.main.web-application-type
属性来修改WEB环境或直接通过setApplicationContextClass(…)来显式指定ApplicationContext的实现!
如果需要设置Bean在使用时才创建,而不是在应用程序启动期间创建,可以设置其延迟初始化,但这会延迟应用程序问题的发现。
对所有Bean进行设置,可以通过spring.main.lazy-initialization=true
属性或setLazyInitialization
方法来实现。
对单个Bean进行设置,可以使用@Lazy(true)
注解,它将会覆盖对所有Bean上的设置。
SpringApplicationRunListener
贯穿SpringBoot启动的全程,是最常用的干涉SpringBoot启动过程的扩展点。
421public interface SpringApplicationRunListener {
2
3 // 调用 springApplication 的 run 方法时立即调用
4 default void starting(ConfigurableBootstrapContext bootstrapContext) {
5 }
6
7 // Environment 构建完成,但在创建ApplicationContext之前
8 default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
9 ConfigurableEnvironment environment) {
10 }
11
12 // 在创建和准备 Applicationcontext之后,但在加载之前
13 default void contextPrepared(ConfigurableApplicationContext context) {
14 }
15
16 // ApplicationContext已加载,但尚未刷新容器时
17 default void contextLoaded(ConfigurableApplicationContext context) {
18 }
19
20 // IOC 容器已刷新,但未调用CommandLineRunners和ApplicationRunners 时
21 default void started(ConfigurableApplicationContext context, Duration timeTaken) {
22 started(context);
23 }
24
25 default void started(ConfigurableApplicationContext context) {
26 }
27
28 // ???
29 default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
30 running(context);
31 }
32
33 // 在 run 方法彻底完成之前
34
35 default void running(ConfigurableApplicationContext context) {
36 }
37
38 // run 方法执行过程中抛出异常时
39 default void failed(ConfigurableApplicationContext context, Throwable exception) {
40 }
41
42}
SpringBoot 内置了 一个 SpringApplicationRunListener 的实现类 EventPublishingRunListener
,用于在上下文启动时发布一些关键事件,提供给使用者干涉上下文启动过程:
在运行开始时,但在进行任何处理之前(侦听器和初始化器的注册除外),发送ApplicationStartingEvent。
当知道要在上下文中使用的Environment时,但在创建上下文之前,发送ApplicationEnvironmentPreparedEvent。
在刷新开始之前,但在加载 bean 定义之后,发送ApplicationPreparedEvent。
在刷新上下文之后,但在调用任何应用程序和命令行运行程序之前,发送ApplicationStartedEvent。
调用任何应用程序和命令行运行程序后,将发送ApplicationReadyEvent。它指示应用程序已准备就绪,可以处理请求。
如果启动时出现异常,则会发送ApplicationFailedEvent。
如下定义了一个 ApplicationStartingEvent 事件的监听器:
71public class ApplicationStartingEventListener implements ApplicationListener<ApplicationStartingEvent> {
2
3 public void onApplicationEvent(ApplicationStartingEvent contextRefreshedEvent) {
4 ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
5 System.out.println("==============Spring容器刷新完毕==============");
6 }
7}
注意,上述部分事件触发时,可能 ApplicationContext 尚未创建完成,可能需要在META-INF/spring.factories
文件中注册上述创建的监听器,如下所示:
71// SpringApplicationBuilder
2new SpringApplicationBuilder(SpringApplicationApplication.class)
3 .listeners(new ApplicationStartingEventListener()).run(args);
4
5// spring.factories
6org.springframework.context.Applicationlistener=\
7 com.linkedbear.springboot.listener.ApplicationStartingEventListener
或者通过使用SpringApplication.addListeners(…)
方法或SpringApplicationBuilder.listeners(…)
方法注册它们。
121
2public class MyApplication {
3 public static void main(String[] args) {
4 SpringApplication springApplication = new SpringApplication(MyApplication.class);
5 springApplication.addListeners(new ApplicationStartingEventListener());
6 springApplication.run(args);
7 }
8}
9
10// SpringApplicationBuilder
11new SpringApplicationBuilder(SpringApplicationApplication.class)
12 .listeners(new ApplicationStartingEventListener()).run(args);
或者在application.properties
文件中进行注册:
21# ApplicationStartingEventListener
2context.listener.classes=com.huangyuanxin.notes.springboot.listener.ApplicationStartingEventListener
此外,还可以通过注册为Bean的方式来注册监听器,但是部分事件是在创建ApplicationContext之前触发的,因此对应的监听器不适用。
ApplicationContextInitializer在Springboot启动过程(refresh方法前)调用,是一种更加简单的介入方式。
71public class MyApplicationContextInitializer implements ApplicationContextInitializer {
2
3 public void initialize(ConfigurableApplicationContext applicationContext) {
4 System.out.println("===========MyApplicationContextInitializer=========");
5 }
6}
7
注册方式和监听器类似,推荐在META-INF/spring.factories
文件中进行注册。
31# ApplicationContextInitializer
2org.springframework.context.ApplicationContextInitializer=com.huangyuanxin.notes.springboot.initializer.MyApplicationContextInitializer
3
当然,也可以使用SpringApplication.addInitializers(…)
方法、SpringApplicationBuilder.initializers(…)
方法或context.initializer.classes
属性注册它们。
EnvironmentPostProcessor可用于在刷新应用程序上下文之前自定义Environment。如下示例从Classpath加载YAML配置文件:
391package com.huangyuanxin.notes.springboot.environment;
2
3import org.springframework.boot.SpringApplication;
4import org.springframework.boot.env.EnvironmentPostProcessor;
5import org.springframework.boot.env.YamlPropertySourceLoader;
6import org.springframework.core.env.ConfigurableEnvironment;
7import org.springframework.core.env.PropertySource;
8import org.springframework.core.io.ClassPathResource;
9import org.springframework.core.io.Resource;
10
11import java.io.IOException;
12
13public class YmlLoadEnvironmentPostProcessor implements EnvironmentPostProcessor {
14
15 private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
16
17
18 public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
19 // 从类路径加载YML文件
20 Resource path = new ClassPathResource("com/huangyuanxin/notes/springboot/my-config.yml");
21 PropertySource<?> propertySource = loadYaml(path);
22
23 // 添加在末尾,优先于其它常见的属性源
24 environment.getPropertySources().addLast(propertySource);
25 }
26
27 private PropertySource<?> loadYaml(Resource path) {
28 if (!path.exists()) {
29 throw new IllegalArgumentException("Resource " + path + " does not exist");
30 }
31
32 try {
33 return this.loader.load("my-config", path).get(0);
34 } catch (IOException ex) {
35 throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
36 }
37 }
38
39}
同样的,你需要在META-INF/spring.factories
中进行注册,而不能通过注册组件的方式来注册它。
31# EnvironmentPostProcessor
2org.springframework.boot.env.EnvironmentPostProcessor=com.huangyuanxin.notes.springboot.environment.YmlLoadEnvironmentPostProcessor
3
提示:EnvironmentPostProcessor还可以用来处理属性加密。
如果在SpringApplication启动的最后,需要运行一些特定的代码,可以实现ApplicationRunner
或CommandLineRunner
接口,两者工作方式一致,仅run方法的参数类型不同。
ApplicationRunner
91// 可直接通过组件注解来注册
2100) // 执行顺序,越小越先执行 (
3public class MyApplicationRunner implements ApplicationRunner {
4
5
6 public void run(ApplicationArguments args) throws Exception {
7 System.out.println("============MyApplicationRunner=============");
8 }
9}
CommandLineRunner
101// 可直接通过组件注解来注册
2200) // 执行顺序,越小越先执行 (
3public class MyCommandLineRunner implements CommandLineRunner {
4
5
6 public void run(String... args) {
7 System.out.println("============MyCommandLineRunner=============");
8 }
9}
10
提示:你可以通过实现
Ordered
接口或使用@Order
注解来调整其执行顺序,值越大越后执行。
如果需要访问启动时的命令行参数,可以通过注入org.springframework.boot.ApplicationArguments
来获取。
241
2public class ApplicationArgumentsTest {
3
4 private ApplicationArguments applicationArguments;
5
6
7 public void init() {
8 // 1. 获取所有原始参数
9 String[] sourceArgs = applicationArguments.getSourceArgs();
10
11 // 2. 获取所有option参数及其值(--开头的参数)
12 Set<String> optionNames = applicationArguments.getOptionNames();
13 for (String optionName : optionNames) {
14 List<String> optionValues = applicationArguments.getOptionValues(optionName);
15 }
16
17 // 3. 判断是否包含某个option参数
18 boolean debug = applicationArguments.containsOption("debug");
19
20 // 4. 获取所有非option参数
21 List<String> nonOptionArgs = applicationArguments.getNonOptionArgs();
22 }
23}
24
除此之外,SpringBoot还向容器注册了一个CommandLinePropertySource。这样就可以使用@Value
注解直接注入单个应用程序参数。
每个应用在启动时都会向JVM注册一个关闭钩子,以确保在退出时正常关闭,保证所有标准的Spring生命周期回调如期生效。
另外,如果希望在调用SpringApplication.exit()时返回特定的退出代码,则可以实现ExitCodeGenerator
接口,然后可以将此退出代码传递给System.exit(),以将其作为状态代码返回,如以下示例所示:
181
2public class MyApplication {
3 public static void main(String[] args) {
4 // 创建和启动
5 SpringApplication springApplication = new SpringApplication(MyApplication.class);
6 ConfigurableApplicationContext context = springApplication.run(args);
7
8 // 关闭应用
9 System.exit(SpringApplication.exit(context));
10 }
11
12 // 设置上下文退出代码
13
14 public ExitCodeGenerator exitCodeGenerator() {
15 return () -> 42;
16 }
17}
18
此外,ExitCodeGenerator接口可能会通过异常实现。遇到此类异常时,Spring Boot 将返回已实现的getExitCode()方法提供的退出代码。
SpringBoot支持使用Properties文件、YAML文件、环境变量和命令行参数等多种方式来配置外部属性,并使用Environment
进行统一管理,然后通过@Value
注解注入到Bean,或通过@ConfigurationProperties
注解绑定到结构化对象后使用。
SpringBoot从不同来源加载的外部属性允许被覆盖,它们之间的优先级如下:
主目录($HOME)中Devtools配置的全局属性(位于~/.spring-boot-devtools.properties)。
通过@TestPropertySource等测试相关注解配置的属性。
命令行参数。
SPRING_APPLICATION_JSON中配置的属性。
来自Web环境的属性:ServletConfig的初始化参数、ServletContext的初始化参数和来自java:comp/env的JNDI属性。
通过System.getProperties()获取的Java系统属性。
系统环境变量。
通过RandomValuePropertySource生成随机值的属性(属性值为random.*前缀)。
特定Profile的配置文件(application-{profile}.properties或类似YAML)(Jar包外部的优先)。
默认配置文件(application.properties或类似YAML)(Jar包外部的优先)。
@Configuration类上的@PropertySource注解加载的配置文件。
通过SpringApplication.setDefaultProperties指定的默认属性。
SpringBoot会将任何命令行选项参数(以--
开头)或JVM属性(以-D
开头)添加到Environment中,如下所示:
11java -jar my-app.jar --name="Spring" --server.port=9000
小提示:
可以使用
SpringApplication.setAddCommandLineProperties(false)
禁用此默认行为。可以在属性值中使用占位符来减短属性长度,如属性
server.port=${port:8080}
,只需通过--port=9000
配置即可。
SPRING_APPLICATION_JSON是通过命令行参数、系统变量、环境属性等其它方式配置的内联JSON,SpringBoot会对其进行展开,提取JSON配置的属性。使用系统变量的配置方式如下:
其它配置方式可参考如下示例:
91# JVM属性
2java -Dspring.application.json='{"name":"test"}' -jar myapp.jar。
3
4# 命令行参数
5java -jar myapp.jar --spring.application.json='{"name":"test"}'。
6
7# 环境属性
8java:comp/env/spring.application.json
9
SpringBoot提供了RandomValuePropertySource
类用于支持随机值的配置,类型可以是int
、long
、uuid
或字符串
等,示例如下:
61# 随机字符串、整型、长整型、UUID
2my.secret=${random.value}
3my.number=${random.int}
4my.bignumber=${random.long}
5my.uuid=${random.uuid}
6
其中random.int
和random.long
属性支持一个范围后缀,其语法为:OPEN value (,max) CLOSE
,其中OPEN和CLOSE可以是任何字符,max是整数。如果提供了max,则value是最小值,max是最大值(不含)。
41# 带范围的随机值
2my.number.less.than.ten=${random.int(10)}
3my.number.in.range=${random.int[1024,65536]}
4
Profiles是一种策略式的组件或配置文件的加载方式,可以方便的切换不同的环境配置,使用时分为标记
和激活
两个步骤。
标记
对于Spring组件可以使用@Profile
注解进行标记:
41
2"prod") // 标记为prod环境 (
3public class ProductionConfiguration {
4}
对于多个配置文件,可通过属性文件名-profile
的方式来标记:
41application.properties
2application-dev.properties
3application-test.properties
4application-prod.properties
对于YML分段文件,可以使用spring.profiles
属性来标记:
181server
2 port8080
3spring
4 profiles
5 active dev # 激活配置
6---
7# 开发环境
8server
9 port8081
10spring
11 profiles dev
12---
13# 生产环境
14server
15 port8083
16spring
17 profiles prod & eu-central
18
激活
可以通过spring.profiles.active
属性来指定需激活的profile列表,该属性可以配置在属性文件中:
11spring.profiles.active=dev,hsqldb
也可以在命令行上指定它:
11java -jar my-app.jar --Dspring.profiles.active=dev,hsqldb
提示:该属性可以被覆盖,这意味着您可以在属性文件中指定默认的active配置,然后使用命令行开关“替换”它们。
附加
有时候,不需要对整个active属性进行替换,而是在此基础上附加一些额外的profile,可以使用spring.profiles.include
属性。
101---
2my.property fromyamlfile
3
4---
5# prod策略,并且级联激活proddb、prodmq策略
6spring.profiles prod
7spring.profiles.include
8 proddb
9 prodmq
10
除此之外,也可以使用编程的方式实现:
11SpringApplication.setAdditionalProfiles(…)
SpringBoot使用application.properties/application.yaml/application.yml(按优先级从高到低排序)
作为默认的属性配置文件,将会从下列路径依次加载,后加载的同名属性会将之前的值覆盖。
ClassPath根目录。
ClassPath/config包。
Jar包执行的当前目录。
Jar包执行的当前目录/config子目录。
如果想修改默认属性文件名,可以使用spring.config.name
进行指定。
31# 指定默认的属性配置文件名为myapplication.properties/myapplication.yaml/myapplication.yml
2java -jar myproject.jar --spring.config.name=myapplication
3
如果想修改默认加载目录,可以使用spring.config.location
指定或通过spring.config.additional-location
进行附加。
61# 指定属性文件加载目录,加载的顺序从后往前(注意:支持特定于Profiles的变体)
2java -jar myproject.jar --spring.config.location=classpath:/,classpath:/config/,file:./,file:./config/
3
4# 附加属性文件加载目录,加载的顺序从后往前(注意:1. 支持特定于Profiles的变体。2. 附加目录优先加载,可能被默认目录下的值覆盖)
5java -jar myproject.jar --spring.config.location=classpath:/,classpath:/config/,file:./,file:./config/
6
如果想同时指定加载目录和属性文件名,也可以使用spring.config.location
属性:
31# 显式指定路径下的某些文件(注意:不支持特定于Profiles件的变体)
2java -jar myproject.jar --spring.config.additional-location=classpath:/custom-config/,file:./custom-config/
3
注意:
由于上述属性在加载属性文件之前被使用,因此你必须使用系统变量、系统属性或命令行参数等高优先级的配置方式。
大多操作系统不支持使用句点分隔的环境变量名,你可以使用下划线形式代替(例如:SPRING_CONFIG_NAME)。
SpringBoot默认从application.properties文件加载属性配置,如果存在其它properties类型的配置文件,可以通过@PropertySource
注解来加载。示例如下:
41
2value = {"com/huangyuanxin/notes/springboot/my-config.properties"}) (
3public class LoadPropertiesConfig {
4}
YAML是JSON的超集,是一种用于指定层次结构配置数据的便捷格式,非常适合用来做以数据为中心的配置文件。spring-boot-starter自动引入了SnakeYAML库用于支持yaml格式,其基本语法如下:
数据格式为key: value
,大小写敏感,并且kv之间必须有空格。
使用缩进表示层级关系,且缩进不允许使用tab,只允许空格。
缩进的空格数不重要,只要相同层级的元素左对齐即可。
注释行使用'#'开头,注意不支持行尾注释。
字符串可以不加引号,如果要加,''与""分别表示字符串内容会被转义和不转义。
可以使用---
对文件进行分段,将多个YML文件整合为一个。
下面是使用yaml配置不同类型数据的语法格式:
211# 1. 字面量类型:单个不可再分的值,如date、boolean、string、number、null等。
2k v
3
4---
5
6# 2. 对象类型:键值对的集合,如object、map、hash、set等。
7k k1 v1 k2:v2 k3:v3
8k
9 k1 v1
10 k2 v2
11 k3 v3
12
13---
14
15# 3. 数组类型:一组按次序排列的值,如array、list、queue等。
16k v1 v2 v3
17k
18 v1
19 v2
20 v3
21
具体案例可参考属性注入和绑定章节!
61// 注入Environment中的spring.application.name属性
2
3public class HelloController {
4 "${spring.application.name}") (
5 private String appName;
6}
注意:
该注解不能在静态变量和常量上使用!
SpringBoot提供了@ConfigurationProperties
注解将属性配置与强类型的JavaBean进行绑定,并且支持宽松的绑定格式、属性值转换、属性值验证及元数据提示等,使用起来更加方便。
有如下一个YML配置文件,已通过YmlLoadEnvironmentPostProcessor
(见第二章节)进行加载:
271# 配置person
2person
3 userName zhangsan
4 bossfalse
5 birth 2019/12/12 20 1233
6 age18
7 pet
8 name tomcat
9 weight23.4
10 interests 篮球 游泳
11 animal
12 jerry
13 mario
14 score
15 english
16 first30
17 second40
18 third50
19 math 131 140 148
20 chinese first128second136
21 salarys 3999 4999.98 5999.99
22 allPets
23 sick
24name tom
25name jerryweight47
26 health name mario weight47
27
我们可以通过如下JavaBean进行属性绑定,绑定后可直接通过容器中的PersonProperty实例使用绑定属性。
251
2prefix = "person") (
3public class PersonProperty {
4 private String userName;
5 private Boolean boss;
6 private Date birth;
7 private Integer age;
8 private Pet pet;
9 private String[] interests;
10 private List<String> animal;
11 private Map<String, Object> score;
12 private Set<Double> salarys;
13 private Map<String, List<Pet>> allPets;
14
15 // getter/setter/toString...
16 }
17
18 static class Pet {
19 private String name;
20 private float weight;
21
22 // getter/setter/toString...
23 }
24}
25
提示:@ConfigurationProperties有一些属性可以控制绑定时的行为。
ignoreUnknownFields
:默认为true,如果设置为false,则在属性文件中提供了属性类没有的属性时报错。
ignoreInvalidFields
:默认为false,如果设置为true,则在属性绑定失败时不报错。
如果该Bean不是Spring组件,则在必须在其它Spring组件上使用@EnableConfigurationProperties(Person.class)
注解将其拉起。
51
2PersonProperty.class) (
3public class MyConfiguration {
4}
5
属性Bean以属性前缀-全类名作为Bean名称,如果未配置属性前缀,则Bean名称为全类名。可以像使用其他任何Bean一样注入该属性Bean并使用,如构造函数注入、@Bean方法注入、@Autowird注入等。
91
2public class MyService {
3 private PersonProperty personProperty;
4
5
6 public MyService(PersonProperty personProperty) {
7 this.personProperty = personProperty;
8 }
9}
注意:
必须为配置的属性提供相关的getter/setter方法及默认构造函数,但二级属性等除外。
不支持对静态属性进行绑定。
使用
@ConfigurationProperties
还可让您生成元数据文件,IDE可以使用这些元数据文件为提供配置提示。
如果需要将属性绑定到不可修改的第三方组件等,可以在@Bean方法上加@ConfigurationProperties
注解来实现:
111
2public class JdbcConfiguration {
3
4
5 // 声明要注入的属性前缀,SpringBoot会自动把相关属性通过set方法注入到DataSource中
6 prefix = "jdbc") (
7 public DataSource dataSource() {
8 DruidDataSource dataSource = new DruidDataSource();
9 return dataSource;
10 }
11}
SpringBoot使用一些宽松的规则将加载的属性绑定到属性Bean,因此属性名称和Bean中的属性名不需要完全匹配。如下示例:
121prefix="acme.my-project.person") (
2public class OwnerProperties {
3 private String firstName;
4
5 public String getFirstName() {
6 return this.firstName;
7 }
8
9 public void setFirstName(String firstName) {
10 this.firstName = firstName;
11 }
12}
可以使用下列一些方式来配置firstName的属性值:
121# 标准驼峰写法
2acme.myProject.person.firstName
3
4# 烤肉串(Kebab)形式,推荐在properties和yml文件中使用
5acme.my-project.person.first-name
6
7# 下划线形式,也推荐在properties和yml文件中使用
8acme.my_project.person.first_name
9
10# 大写下划线形式,一般在系统环境变量中使用
11ACME_MYPROJECT_PERSON_FIRSTNAME
12
注意:
前提:@ConfigurationProperties注解中的
prefix
属性必须是小写且由-
分隔的形式,如acme.my-project.person
。属性名建议使用小写的 kebab 格式存储,例如
my.property-name=acme
。如需在环境变量中配置列表数据,可以使用带下划线的数字值表示,如
MY_ACME_1_OTHER = my.acme[1].other
。绑定到Map属性时,如果key包含小写字母、数字字符或-以外的任何内容,则必须使用
[]
括起来,否则将会被删除。51# 如下Map的配置效果为:/key1=value1,key2:value2
2acme
3map
4"[/key1]" value1
5/key2 value2
默认情况下,SpringBoot会直接覆盖旧的属性值,但对于复杂类型,做了一些特殊处理。
List类型属性
如果在多个属性源配置了同名的List属性,处理方式和基本属性一致,采用完全覆盖的方式,取优先级最高的配置。如下属性:
91"acme") (
2public class AcmeProperties {
3 private final List<MyPojo> list = new ArrayList<>();
4
5 public List<MyPojo> getList() {
6 return this.list;
7 }
8}
9
在外部属性源存在多个list的配置如下:
111acme
2 list
3name my name
4 description my description
5---
6spring
7 profiles dev
8acme
9 list
10name my another name
11
最终生效情况如下:
91# 情形一:未激活dev
2list
3name my name
4 description my description
5
6# 情形二:激活dev
7list
8name my another name
9
Map类型属性
如果在多个属性源配置了同名的Map属性,采用合并的方式进行处理。如下属性:
91"acme") (
2public class AcmeProperties {
3 private final Map<String, MyPojo> map = new HashMap<>();
4
5 public Map<String, MyPojo> getMap() {
6 return this.map;
7 }
8}
9
在外部属性源存在多个map的配置如下:
161acme
2 map
3 key1
4 name my name 1
5 description my description 1
6---
7spring
8 profiles dev
9acme
10 map
11 key1
12 name dev name 1
13 key2
14 name dev name 2
15 description dev description 2
16
最终生效情况如下:
171# 未激活dev
2acme
3 map
4 key1
5 name my name 1
6 description my description 1
7
8# 激活dev(合并了默认配置中key1.description属性)
9acme
10 map
11 key1
12 name dev name 1
13 description my description 1
14 key2
15 name dev name 2
16 description dev description 2
17
在SpringBoot绑定属性时,会尝试将外部属性值强制转换为对应的类型。
Duration类型
Duration类型专门用于表达持续时间,SpingBoot在属性绑定时对其做了特殊处理。支持下面一些格式:
常规long表示形式(使用毫秒作为默认单位,除非已指定@DurationUnit)。
由 java.util.Duration使用的标准 ISO-8601 格式。
值和单位相结合的更易读的格式(例如10s表示10秒),常见的单位还有:ns、us、ms、s、m、h、d等。
121"app.system") (
2public class AppSystemProperties {
3 // 属性可以配置如30 PT30S 30s等
4 (ChronoUnit.SECONDS)
5 private Duration sessionTimeout = Duration.ofSeconds(30);
6
7 // 属性可以配置如500 PT0.5S 500ms等
8 private Duration readTimeout = Duration.ofMillis(1000);
9
10 // 省略getter/setter
11}
12
DataSize类型
DataSize类型专门用于表达数据大小,SpingBoot在属性绑定时对其做了特殊处理。支持下面一些格式:
常规的long表示形式(除非已指定@DataSizeUnit,否则使用字节作为默认单位)。
值和单位耦合在一起的更具可读性的格式(例如10MB表示10兆字节),常见的单位还有:B、KB、MB、GB、TB等。
131"app.io") (
2public class AppIoProperties {
3
4 // 属性可以配置如:10、10MB
5 (DataUnit.MEGABYTES)
6 private DataSize bufferSize = DataSize.ofMegabytes(2);
7
8 // 属性可以配置如:256、256B
9 private DataSize sizeThreshold = DataSize.ofBytes(512);
10
11 // 省略getter/setter
12}
13
自定义类型
如果需要自定义类型转换,可以使用属性编辑器(CustomEditorConfigurer)、Converters(@ConfigurationPropertiesBinding)或ConversionService(名称为conversionService的Bean)等。
注意:该类型Bean在生命周期中非常早的初始化,请注意所使用的依赖。
在绑定属性时,如果Classpath上有兼容的JSR-303 实现,那么还支持JSR-303标准定义的@Validated
注解进行属性值的验证。
201prefix="acme") (
2// 启用验证
3public class AcmeProperties {
4
5 private InetAddress remoteAddress;
6
7
8 private final Security security = new Security();
9
10 // ... getters and setters
11
12 public static class Security {
13
14 public String username;
15
16 // ... getters and setters
17 }
18}
19
20
除此之外,也可以通过在创建属性Bean的@Bean方法上使用@Validated注解来触发验证。
注意: 尽管嵌套属性在绑定时也会验证,但是最好将关联的字段注解为@Valid。这样可以确保即使没有嵌套属性也可以触发验证。
如果需要对Validator进行扩展,可以创建名为configurationPropertiesValidator
的bean来添加自定义Spring Validator,但注意,其@Bean方法应声明为static(防止配置属性验证器过早实例化)。
对于一些开源或商业项目,或者是其它的一些共享Jar包,可能也希望使用SpringBoot提供的自动配置功能,下面将会介绍如何使用。
AutoConfiguration类是SpringBoot中用于实现自动配置的特殊配置类,其通过一系列的条件注解约束配置在特定的条件下才会生效。
如需使SpringBoot识别自定义的自动配置类,则必须在类路径下的META-INF/spring.factories
文件中进行配置。
41org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2com.szkingdom.koca.boot.autoconfigure.bex.BexAutoConfiguration,\
3com.szkingdom.koca.boot.autoconfigure.context.ContextAutoConfiguration
4
如果需要指定自动配置类的加载顺序,可以通过@AutoConfigureOrder
注解来声明,它和Spring的Order注解类似。除此之外,也可以通过@AutoConfigureAfter
或@AutoConfigureBefore
注解来配置指定Bean之间的先后顺序。
注意:自动配置类一般在@Configuration上加proxyBeanMethods=false属性,表示禁止代理@Bean方法,这样在代码中显式调用@Bean方法时不会返回容器中已存在的值。
条件注解@Conditional
是实现自动配置的关键,SpringBoot支持许多类型的条件注解。
类条件
@ConditionalOnClass
和@ConditionalOnMissingClass
使自动配置仅在特定类存在/缺失时生效。可以使用value
属性直接引用特定的类,或使用name
属性指定其字符串形式的全类名。
111
2AppContext.class, AppLoadListener.class}) // 当类路径下存在AppContext和AppLoadListener时该配置才会生效 ({
3-2147473648) // 指定加载顺序,数值越小越先加载 (
4public class ContextAutoConfiguration {
5 "koca-core-application-context"}) ({
6
7 public AppContext appContext() {
8 return new AppContext();
9 }
10}
11
注意:
由于注解的元数据是通过ASM进行解析的,因此即使引用的类不在类路径上,也可以使用value属性进行引用。
但上述注解形成的组合注解,无法使用value属性引用类路径下不存在的类。
Bean条件
@ConditionalOnBean
和@ConditionalOnMissingBean
使自动配置仅在特定的Bean存在/缺失时生效。可以使用value
属性指定Bean的类型,如果该注解加在@Bean方法上,则默认值为方法的返回值类型。此外,也可以使用name
属性指定Bean的名称。
71
2public class MyAutoConfiguration {
3
4 // 当容器中不存在MyService类型的Bean时,则该配置生效
5 public MyService myService() { ... }
6}
7
除此之外,还可以使用search
属性限制搜索Bean时应考虑的ApplicationContext层次结构。
注意:
该条件注解是根据当前已处理的内容来评估的,因此需要特定注意Bean的初始化顺序。
属性条件
@ConditionalOnProperty
使自动配置仅在Spring环境中包含特定的属性时生效。分别使用prefix
和name
属性来指定应检查的属性,默认情况下,当检测的属性存在且不等于false时生效。
你可以使用havingValue
属性来设置与之对比的值,当属性存在且值相同时则加载。matchIfMissing
属性可以设置指定的属性不存在时是否进行加载。
31// 检查com.huangyuanxin.autocheck.enabled属性是否为true。在属性不存在默认配置生效。
2prefix = "com.huangyuanxin.autocheck", name = "enabled", havingValue = true, matchIfMissing = true) (
3
资源条件
@ConditionalOnResource
使自动配置仅在特定资源存在时才生效,使用通常的Spring约定来指定资源,如:file:/home/user/test.dat。
Web环境
@ConditionalOnWebApplication
和@ConditionalOnNotWebApplication
使自动配置仅在Web环境下生效。Web环境指使用了WebApplicationContext,或定义了session范围,或具有StandardServletEnvironment的环境。
SpEL条件
@ConditionalOnExpression
注解允许基于SpEL expression的结果决定配置是否生效。
byType条件
@ConditionalOnSingleCandidate注解使自动配置仅在当容器中具有唯一的该类型Bean(或存在主候选对象)时生效。
11DataSource.class) (
自定义条件
141// 基于条件装配Bar组件
2
3ExistBossCondition.class) (
4public Bar bbbar (){
5 return new Bar();
6}
7
8// 装配条件判断
9public class ExistBossCondition implements Condition {
10
11 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata){
12 return context.getBeanFactory().containsBeanDefinition(Boss.class.getName());
13 }
14}
启动器是为某个使用场景提供的一系列依赖和自动配置的集合。通常来说,可以将启动器分为两个部分:
autoconfigure模块:通过条件注解实现自动配置等功能,通常以-spring-boot-autoconfigure
结尾。
starter模块:直接引用autoconfigure模块,并引入一些必要的依赖和进行相关配置,通常以-spring-boot-start
结尾。
实际开发中,也可以将autoconfigure模块直接合并到starter模块之中。
注意:
启动器必须直接或间接的引用核心Spring Boot启动程序spring-boot-starter。
如果启动器需要暴露自定义属性,可以通过下面注解处理器来生成元数据文件(META-INF/spring-configuration-metadata.json),以便IDE进行配置提示。
51<dependency>
2<groupId>org.springframework.boot</groupId>
3<artifactId>spring-boot-autoconfigure-processor</artifactId>
4<optional>true</optional>
5</dependency>
自动配置可通过一些特殊的方式来进行测试,详情请查看官方文档。
每个SpringBoot Web应用程序都包含一个嵌入式Web服务器,下面介绍如何进行替换和配置。
基于Servlet的Web应用程序(spring-boot-starter-web),默认的嵌入式服务器为Tomcat
,你可以通过如下配置来替换为Jetty
或Undertow
等。
241<properties>
2 <!--修改Servlet版本(Jetty9.4不支持Servlet4.0)-->
3 <servlet-api.version>3.1.0</servlet-api.version>
4</properties>
5
6<dependency>
7 <groupId>org.springframework.boot</groupId>
8 <artifactId>spring-boot-starter-web</artifactId>
9 <exclusions>
10 <!-- 排除默认的Tomcat启动器 -->
11 <exclusion>
12 <groupId>org.springframework.boot</groupId>
13 <artifactId>spring-boot-starter-tomcat</artifactId>
14 </exclusion>
15 </exclusions>
16</dependency>
17
18<!-- 使用Jetty启动器 -->
19<dependency>
20 <groupId>org.springframework.boot</groupId>
21 <artifactId>spring-boot-starter-jetty</artifactId>
22</dependency>
23
24
基于Reactive的Web应用程序(spring-boot-starter-webflux),默认的嵌入式服务器启动器为spring-boot-starter-reactor-netty
,你可以通过spring-boot-starter-tomcat、spring-boot-starter-jetty或spring-boot-starter-undertow来进行替换。
如果类路径下包含相关的依赖项,将自动启动嵌入式Web服务器,但可以通过spring.main.web-application-type=none
属性来禁用它。
可以使用server.port
属性来设置Web服务器的HTTP端口,默认的端口号为8080。
81# 设置自定义HTTP端口
2server.port=8081
3
4# 自动扫描可用的端口
5server.port=0
6
7# 关闭HTTP端口,但仍创建WebApplicationContext(用于测试)
8server.port=-1
如需在应用运行时获取HTTP端口,可以监听WebServerInitializedEvent
事件(Web服务器启动完成时触发)。
101
2public void onWebServerInitialized(WebServerInitializedEvent event) {
3 if ("server".equals(event.getServerId())) {
4 localServerPort = event.getWebServer().getPort();
5 }
6 if ("management".equals(event.getServerId())) {
7 localManagementPort = event.getWebServer().getPort();
8 }
9}
10
如需获取测试时@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)生成的随机端口,可以通过@LocalServerPort
注解注入,或通过local.server.port
属性获取。
101SpringJUnit4ClassRunner.class) (
2webEnvironment=WebEnvironment.RANDOM_PORT) (
3public class MyWebIntegrationTests {
4
5 ServletWebServerApplicationContext server;
6
7
8 int port;
9}
10
201# 配置Tomcat访问日志
2server.tomcat.basedir=tomcat-log # 日志生成目录(该目录下的logs目录下)
3server.tomcat.accesslog.enabled=true # 开启访问日志
4server.tomcat.accesslog.prefix=demo-log # 日志前缀
5server.tomcat.accesslog.suffix=.log # 日志后缀
6server.tomcat.accesslog.file-date-format=.yyyyMMdd # 日志日期格式
7server.tomcat.accesslog.pattern=%h %l %u %t \"%r"\ %s %b # 日志内容格式(%h 请求的客户端IP、%l 用户身份、%u 用户名、%t 请求时间、%r 请求地址、%s 响应状态码、%b 响应大小)
8logging.level.org.apache.tomcat = debug; #开启服务器内部日志
9logging.level.org.apache.catalina = debug; #开启服务器内部日志
10
11
12# 配置Undertow访问日志 server.undertow.accesslog.directory
13server.undertow.accesslog.enabled=true
14server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)
15
16
17# 配置Jetty访问日志
18server.jetty.accesslog.enabled=true
19server.jetty.accesslog.filename=/var/log/jetty-access.log
20
如果需要修改相关配置,可以在application.properties文件中修改,常用的配置如下:
配置属性 | 说明 |
---|---|
server.port | HTTP 请求的端口 |
server.servlet.session.persistence | 会话是否持久 |
server.servlet.session.timeout | 会话超时时间 |
server.servlet.session.store-dir | 会话数据的位置 |
server.servlet.session.cookie.* | 会话 cookie 配置 |
server.error.path | 错误页面的位置 |
注意:
关于Servlet容器的更多配置请参考
ServerProperties
类,其中还包含了一些如server.tomcat.*
前缀的特定于容器的配置。如果在CentOS上使用Tomcat,生成的临时文件可能被自动清理,可使用
server.tomcat.basedir
属性配置到其它位置。
嵌入式Tomcat、Jetty和Undertow服务器都支持HTTP响应压缩,可通过如下属性来开启和配置。
81# 开启HTTP响应压缩,默认关闭
2server.compression.enabled=true
3
4# 响应长度阈值,低于该值时不进行压缩,默认为2048字节
5server.compression.min-response-size=2048
6
7# 只对指定Content Type的响应进行压缩,默认支持text/html、text/xml、text/plain、text/css、text/javascript、application/javascript、application/json、application/xml
8server.compression.mime-types=application/json
HTTPS是以安全为目标的HTTP通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。在SpringBoot应用程序中可以通过server.ssl.*
前缀的相关属性来配置SSL以支持HTTPS。
51server.port=8443
2server.ssl.key-store=classpath:keystore.jks
3server.ssl.key-store-password=secret
4server.ssl.key-password=another-secret
5
提示:更多属性配置可参考源代码:org.springframework.boot.web.server.Ssl.java。
如果需要同时支持HTTP和HTTPS,可参考spring-boot-sample-tomcat-multi-connectors案例给Tomcat配置额外的HTTP连接器。
221
2public class SampleTomcatTwoConnectorsApplication {
3
4
5 public ServletWebServerFactory servletContainer() {
6 TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
7 tomcat.addAdditionalTomcatConnectors(createStandardConnector());
8 return tomcat;
9 }
10
11 private Connector createStandardConnector() {
12 Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
13 connector.setPort(0);
14 return connector;
15 }
16
17 public static void main(String[] args) {
18 SpringApplication.run(SampleTomcatTwoConnectorsApplication.class, args);
19 }
20
21}
22
当然,也可以直接通过编程方式添加HTTPS连接器来同时支持HTTP和HTTPS,如下所示:
301@Bean
2public ServletWebServerFactory servletContainer() {
3TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
4tomcat.addAdditionalTomcatConnectors(createSslConnector());
5return tomcat;
6}
7
8private Connector createSslConnector() {
9Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
10Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
11try {
12File keystore = new ClassPathResource("keystore").getFile();
13File truststore = new ClassPathResource("keystore").getFile();
14connector.setScheme("https");
15connector.setSecure(true);
16connector.setPort(8443);
17protocol.setSSLEnabled(true);
18protocol.setKeystoreFile(keystore.getAbsolutePath());
19protocol.setKeystorePass("changeit");
20protocol.setTruststoreFile(truststore.getAbsolutePath());
21protocol.setTruststorePass("changeit");
22protocol.setKeyAlias("apitester");
23return connector;
24}
25catch (IOException ex) {
26throw new IllegalStateException("can't access keystore: [" + "keystore"
27+ "] or truststore: [" + "keystore" + "]", ex);
28}
29}
30
HTTP/2
也被称为HTTP 2.0,相对于HTTP 1.1新增多路复用、压缩HTTP头、划分请求优先级、服务端推送等特性,解决了在HTTP 1.1中一直存在的问题,优化了请求性能,同时兼容了HTTP 1.1的语义。
SpringBoot应用程序可以通过如下属性来开启HTTP/2支持。
31# 开启HTTP/2支持
2server.http2.enabled=true
3
注意:
Spring Boot不支持h2c,即HTTP/2 协议的明文版本。因此您必须首先配置SSL。
基本环境要求:
Undertow1.4.0+:只需要JDK8+环境。
Jetty9.4.8+:还需要附加依赖项org.eclipse.jetty:jetty-alpn-conscrypt-server和org.eclipse.jetty.http2:http2-server。
Tomcat 9.0.x:最好为JDK9+,也可以使用JDK8,则需要添加libtcnative库及其依赖项(-Djava.library.path=/usr/local/opt/tomcat-native/lib)。
如果提供的属性配置无法满足你对Web服务器的配置需要,还可以通过实现WebServerFactoryCustomizer
接口来自定义Web服务器。
101// 配置Tomcat服务器(Jetty和Undertow服务器同理)
2
3public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
4
5
6 public void customize(TomcatServletWebServerFactory factory) {
7 // 在此处可以配置连接器、服务器资源或服务器本身
8 }
9}
10
作为最终的手段,你还可以定义自己的WebServerFactory
组件,来覆盖掉Spring Boot提供的对应组件,但是在这种情况下,您不能再依赖server名称空间中的配置属性。
81
2public ConfigurableServletWebServerFactory webServerFactory() {
3 TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
4 factory.setPort(9000);
5 factory.setSessionTimeout(10, TimeUnit.MINUTES);
6 factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
7 return factory;
8}
提示:如果您需要做一些更奇特的操作,还提供了几种受保护的方法“钩子”。有关详情,请参见源代码文档。
SpringBoot中默认使用JCL(Common Logging)
日志门面记录所有内部日志,并为JUL
、Log4J2
和Logback
提供了默认配置,支持输出到控制台或文件。
如果引入了某个日志实现,则会激活对应的默认日志配置。目前支持的日志实现有:
日志实现 | 默认配置文件(通过logging.config 属性可修改) |
---|---|
Logback | logback.xml、logback-spring.xml、logback.groovy、logback-spring.groovy |
Log4j2 | log4j2.xml、log4j2-spring.xml |
JUL | logging.properties |
注意:
推荐使用以
-spring
结尾的日志配置文件,否则Spring无法控制日志初始化。不推荐在以java -jar方式运行时使用JUL日志实现,可能会引发类加载错误。
特殊的,如果使用了spring-boot-starter-web,则会切换为Logback
日志实现,默认级别为INFO
,还包括了适当的Logback路由,以确保使用其它日志框架从属库均能正常工作。
SpringBoot默认将日志输出到控制台,打印ERROR
、WARN
和INFO
级别的日志,可以通过debug=true
、trace=true
等属性进行修改,或在应用启动时通过命令行来指定日志级别:java -jar my-app.jar --trace
。
如果需要进行更详细的日志级别控制,可以在通过logging.level.<logger-name>=<level>
格式的属性修改。其中logger-name为具体的Logger,level为日志级别,可选的值有:TRACE
、DEBUG
、INFO
、WARN
、ERROR
、FATAL
或OFF
。
41logging.level.root=WARN
2logging.level.org.springframework.web=DEBUG
3logging.level.org.hibernate=ERROR
4
注意:Logback框架没有FATAL级别,它将会被映射到ERROR。
下面是一些可用的日志配置属性,以及通过系统属性配置时的属性名:
Spring Environment | System Property | Comments |
---|---|---|
logging.exception-conversion-word | LOG_EXCEPTION_CONVERSION_WORD | 记录异常时使用的转换字 |
logging.file | LOG_FILE | 日志文化目录和文件名 |
logging.file.max-size | LOG_FILE_MAX_SIZE | 最大日志文件大小(默认为10M,后缀可以为KB、MB和GB) |
logging.file.max-history | LOG_FILE_MAX_HISTORY | 要保留的最大归档日志文件数(默认无限制) |
logging.path | LOG_PATH | 日志文件目录,默认文件名为spring.log |
logging.pattern.console | CONSOLE_LOG_PATTERN | 在控制台上使用的日志模式(stdout) |
logging.pattern.dateformat | LOG_DATEFORMAT_PATTERN | 记录日期格式的附加模式 |
logging.pattern.file | FILE_LOG_PATTERN | 文件中使用的日志模式 |
logging.pattern.level | LOG_LEVEL_PATTERN | 渲染日志级别时使用的格式(默认为%5p) |
PID | PID | 当前进程ID |
注意:日志功能在创建容器之前进行初始化,因此必须通过系统属性或更高级别的属性配置方式来修改日志属性。
使用Web启动器时,会自动引入SLF4J和Logback的相关依赖,可通过logback.xml
或logback-spring.xml
对其进行配置。
SpringBoot在org/springframework/boot/logging
目录下提供一份base.xml
文件,对LogBack进行了一些默认配置:
111<included>
2 <include resource="org/springframework/boot/logging/logback/defaults.xml" />
3 <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
4 <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
5 <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
6 <root level="INFO">
7 <appender-ref ref="CONSOLE" />
8 <appender-ref ref="FILE" />
9 </root>
10</included>
11
你可以在你的LogBack配置文件中通过如下方式引入来使用:
61
2<configuration>
3 <include resource="org/springframework/boot/logging/logback/base.xml"/>
4 <logger name="org.springframework.web" level="DEBUG"/>
5</configuration>
6
当然,也可以从零开始定义你自己的配置:
341
2<configuration >
3 <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.sss} %c %M %L %thread %m%n"/>
4 <!-- 配置文件输出路径 -->
5 <property name="logDir" value="./logs"/>
6 <!-- 配置控制台 appender -->
7 <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
8 <target>
9 System.err
10 </target>
11 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
12 <pattern>${pattern}</pattern>
13 </encoder>
14 </appender>
15
16 <!-- 配置文件 appender -->
17 <appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
18 <!-- 引入文件位置 -->
19 <file>${logDir}/logback.log</file>
20 <!-- 配置日志输出格式 -->
21 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
22 <!-- 引用 输出格式的 通用配置属性 -->
23 <pattern>${pattern}</pattern>
24 </encoder>
25 </appender>
26
27 <!-- 配置日志记录器 -->
28 <root level="info">
29 <!-- 引入appender -->
30 <appender-ref ref="consoleAppender"></appender-ref>
31 <appender-ref ref="fileAppender"></appender-ref>
32 </root>
33</configuration>
34
如果通过logback-spring.xml
或logging.config
属性指定的其它文件来配置logback,则可以使用一些SpringBoot提供的扩展功能。
支持profile
通过<springProfile>
标签可以方便的将配置切换到不同环境。
121<springProfile name="staging">
2 <!-- configuration to be enabled when the "staging" profile is active -->
3</springProfile>
4
5<springProfile name="dev | staging">
6 <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
7</springProfile>
8
9<springProfile name="!production">
10 <!-- configuration to be enabled when the "production" profile is not active -->
11</springProfile>
12
引入Spring属性
通过<springProperty>
标签可以在logback-spring.xml文件中访问Spring环境属性。
81<!--在context范围(scope属性配置,默认为local)配置一个fluentHost变量,引用Spring的myapp.fluentd.host属性值,如未找到,则默认为localhost-->
2<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/>
3
4<!--在appender中使用fluentHost变量-->
5<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
6 <remoteHost>${fluentHost}</remoteHost>
7</appender>
8
注意:
如果使用logback默认的logback.xml配置文件,将会被过早的加载,无法使用扩展功能。
这些扩展不能与Logback的配置扫描一起使用。
181<!--排除Logback依赖-->
2<dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-web</artifactId>
5 <exclusions>
6 <exclusion>
7 <groupId>org.springframework.boot</groupId>
8 <artifactId>spring-boot-starter-logging</artifactId>
9 </exclusion>
10 </exclusions>
11</dependency>
12
13<!--引入Log4j2启动器-->
14<dependency>
15 <groupId>org.springframework.boot</groupId>
16 <artifactId>spring-boot-starter-log4j2</artifactId>
17</dependency>
18
891
2<Configuration status="fatal">
3 <!--配置log日志文件路径 -->
4 <Properties>
5 <!--配置mac或者linux环境下日志文件路径 -->
6 <!-- <Property name="baseDir" value="${sys:user.home}/logs"/>-->
7
8 <!--配置windows环境下日志文件路径 -->
9 <Property name="baseDir" value="D:\Workspace\shoppingproject\shoppingProject\src\main\resources\logs"/>
10 </Properties>
11
12 <Appenders>
13 <Console name="Console" target="SYSTEM_OUT">
14 <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
15 <ThresholdFilter level="info" onMatch="ACCEPT"
16 onMismatch="DENY"/>
17 <PatternLayout
18 pattern="[%d{MM:dd HH:mm:ss.SSS}] [%level] [%logger{36}] - %msg%n"/>
19 </Console>
20
21 <!--debug级别日志文件输出-->
22 <RollingFile name="debug_appender" fileName="${baseDir}/debug.log"
23 filePattern="${baseDir}/debug_%i.log.%d{yyyy-MM-dd}">
24 <!-- 过滤器 -->
25 <Filters>
26 <!-- 限制日志级别在debug及以上在info以下 -->
27 <ThresholdFilter level="debug"/>
28 <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
29 </Filters>
30 <!-- 日志格式 -->
31 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
32 <!-- 策略 -->
33 <Policies>
34 <!-- 每隔一天转存 -->
35 <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
36 <!-- 文件大小 -->
37 <SizeBasedTriggeringPolicy size="100 MB"/>
38 </Policies>
39 </RollingFile>
40
41 <!-- info级别日志文件输出 -->
42 <RollingFile name="info_appender" fileName="${baseDir}/info.log"
43 filePattern="${baseDir}/info_%i.log.%d{yyyy-MM-dd}">
44 <!-- 过滤器 -->
45 <Filters>
46 <!-- 限制日志级别在info及以上在error以下 -->
47 <ThresholdFilter level="info"/>
48 <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
49 </Filters>
50 <!-- 日志格式 -->
51 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
52 <!-- 策略 -->
53 <Policies>
54 <!-- 每隔一天转存 -->
55 <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
56 <!-- 文件大小 -->
57 <SizeBasedTriggeringPolicy size="100 MB"/>
58 </Policies>
59 </RollingFile>
60
61 <!-- error级别日志文件输出 -->
62 <RollingFile name="error_appender" fileName="${baseDir}/error.log"
63 filePattern="${baseDir}/error_%i.log.%d{yyyy-MM-dd}">
64 <!-- 过滤器 -->
65 <Filters>
66 <!-- 限制日志级别在error及以上 -->
67 <ThresholdFilter level="error"/>
68 </Filters>
69 <!-- 日志格式 -->
70 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
71 <Policies>
72 <!-- 每隔一天转存 -->
73 <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
74 <!-- 文件大小 -->
75 <SizeBasedTriggeringPolicy size="100 MB"/>
76 </Policies>
77 </RollingFile>
78 </Appenders>
79 <Loggers>
80 <Root level="debug">
81 <AppenderRef ref="Console"/>
82 <AppenderRef ref="debug_appender"/>
83 <AppenderRef ref="info_appender"/>
84 <AppenderRef ref="error_appender"/>
85 </Root>
86 <!--配置其它Logger...-->
87 </Loggers>
88</Configuration>
89
当引入com.fasterxml.jackson.core:jackson-databind依赖后,可以使用JSON格式来配置Log4j2,默认配置文件名为log4j2.jsn
。
当引入jackson-databind和com.fasterxml.jackson.dataformat:jackson-dataformat-yaml依赖后,可以使用YML格式来配置Log4j2,默认配置文件名为log4j2.yaml(yml)
。
可以将一些相关的Logger组合为一个日志组,以便同时对它们进行配置。
21# 将tomcat所有顶级Logger配置到tomcat日志组
2logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
定义后,您可以使用一行配置更改该组中所有Logger的级别:
11logging.level.tomcat=TRACE
为了方便web和sql相关日志的配置,SpringBoot内置了一些日志组:
Name | Loggers |
---|---|
web | org.springframework.core.codec , org.springframework.http , org.springframework.web |
sql | org.springframework.jdbc.core , org.hibernate.SQL |
如果终端支持ANSI彩色输出的相关标准,可以通过spring.output.ansi.enabled
属性来设置其行为,可选的值有:DETECT(自动检测,默认值)
、ALWAYS
、NEVER
。
在日志中,可以通过使用%clr
转换字来配置颜色编码。转换器以最简单的形式根据对数级别为输出着色,如:%clr(%5p)
。
下表描述了日志级别到颜色的对应关系:
Level | Color |
---|---|
FATAL | Red |
ERROR | Red |
WARN | Yellow |
INFO | Green |
DEBUG | Green |
TRACE | Green |
如果需要对某段文本进行特殊的修改,可以使用如下形式:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
,支持的颜色还有:red、blue、green、yellow、cyan、faint和magenta。
首先导入整合 JDBC 的依赖:
121<!-- Spring Boot JDBC 启动器 -->
2<dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-jdbc</artifactId>
5</dependency>
6
7<!-- MySql JDBC驱动 -->
8<dependency>
9 <groupId>mysql</groupId>
10 <artifactId>mysql-connector-java</artifactId>
11 <version>5.1.47</version>
12</dependency>
再使用spring.datasource.*
前缀配置一个数据源:
81# 通用配置、
2spring.datasource.driver-class-name=com.mysql.jdbc.Driver
3spring.datasource.url=jdbc:mysql://localhost/test
4spring.datasource.username=dbuser
5spring.datasource.password=dbpass
6
7# hikari数据源的个性化配置(其它数据源类似)
8spring.datasource.hikari.* = xxxxx
SpringBoot会依次查找类路径下的HikariCP
、Tomcat PooledDataSource
、Commons DBCP2
作为数据源实现,你也可以使用spring.datasource.type
属性来显式指定。
注意:
如果使用 spring-boot-starter-jdbc 或spring-boot-starter-data-jpa启动器,则会自动获得
HikariCP
的依赖项。通常不需要指定driver-class-name,因为Spring Boot可以从url推导大多数数据库。
如果未配置spring.datasource.url属性,则Spring Boot会尝试自动配置嵌入式数据库。
有关更多受支持的选项,请参见
DataSourceProperties
。
可以在启动类加上@EnableTransactionManagement
注解,开启声明式事务控制,之后就可以通过@Transactional(rollbackFor =Exception.class)
开事务控制了。
71
2
3public class SpringBootJdbcApplication {
4 public static void main(String[] args) {
5 SpringApplication.run(SpringBootJdbcApplication.class, args);
6 }
7}
@EnableTransactionManagement 注解的一些用法:
该注解不是必须加的,在自动配置类
TransactionAutoConfiguration
中会默认开启声明式事务。该注解的proxyTargetClass 属性:配置是否强制代理目标类(CGLIB),默认为false。
该注解的 mode 属性:配置是否使用类加载时编织(ASPECTJ)实现AOP,默认通过运行期的动态代理(PROXY)来实现AOP,如果需要开启,需额外导入 spring-aspects 依赖。
此外,SpringBoot会自动查找数据源来配置JdbcTemplate
和NamedParameterJdbcTemplate
,可以直接在代码中注入使用。
101
2public class MyBean {
3 private final JdbcTemplate jdbcTemplate;
4
5
6 public MyBean(JdbcTemplate jdbcTemplate) {
7 this.jdbcTemplate = jdbcTemplate;
8 }
9}
10
注意:
当容器中仅存在一个DataSource时(或存在主候选对象),才会配置JdbcTemplate。
当容器中仅存在一个JdbcTemplate时(或存在主候选对象),才会配置NamedParameterJdbcTemplate。
您可以使用spring.jdbc.template.*
来自定义模板的某些属性,如以下示例所示,其它属性可参考JdbcProperties.Template属性类。
11spring.jdbc.template.max-rows=500
如果需要自定义数据源(DataSource),可以手动创建一个DataSource
实现,然后注入到容器中即可,Spring会在任何需要的地方使用它(包括数据库初始化时)。
61
2prefix="app.datasource") (
3public DataSource dataSource() {
4 return new FancyDataSource();
5}
6
和其它常规Bean一样,可以通过@ConfigurationProperties
注解或其它方式来进行外部化配置。
81# 数据源配置(驱动类会根据URL自动解析)
2# app.datasource.jdbc-url=jdbc:mysql://localhost/test Hikari数据源的URL属性key为jdbc-url
3app.datasource.url=jdbc:h2:mem:mydb
4app.datasource.username=dbuser
5app.datasource.password=dbpass
6app.datasource.maximum-pool-size=30
7app.datasource.first.configuration.maximum-pool-size=30 # Hikari数据源的特殊属性
8
此外,自定义数据源也可以通过Spring提供的DataSourceBuilder
工具类创建。
141// 一般数据源
2
3"app.datasource") (
4public DataSource dataSource() {
5 return DataSourceBuilder.create().build();
6}
7
8// 针对Hikari数据源
9
10"app.datasource") (
11public HikariDataSource dataSource() {
12 return DataSourceBuilder.create().type(HikariDataSource.class).build();
13}
14
或可以直接通过DataSourceProperties
映射来创建:
171// 数据源的属性(通用属性,兼容Hikari数据源)
2
3
4"app.datasource") (
5public DataSourceProperties dataSourceProperties() {
6 return new DataSourceProperties();
7}
8
9// 创建数据源,并从app.datasource.configuration中注入自定义属性
10
11"app.datasource.configuration") (
12public HikariDataSource dataSource(DataSourceProperties properties) {
13 return properties.initializeDataSourceBuilder().type(HikariDataSource.class)
14 .build();
15}
16
17
可以使用同样的方式配置两个数据源,但必须将其中一个标记为@Primary
,以便其它地方能够通过类型来获取数据源实例。
241// 第一个数据源的属性
2
3
4"app.datasource.first") (
5public DataSourceProperties firstDataSourceProperties() {
6 return new DataSourceProperties();
7}
8
9// 创建第一个数据源(Hikari类型),同时注入一些特定于数据源的配置,并作为主数据源
10
11
12"app.datasource.first.configuration") (
13public HikariDataSource firstDataSource() {
14 return firstDataSourceProperties().initializeDataSourceBuilder()
15 .type(HikariDataSource.class).build();
16}
17
18// 创建第二个数据源,从数据源
19
20"app.datasource.second") (
21public BasicDataSource secondDataSource() {
22 return DataSourceBuilder.create().type(BasicDataSource.class).build();
23}
24
下面是一个外部化配置的示例:
131# 配置第一个数据源
2app.datasource.first.url=jdbc:mysql://localhost/first
3app.datasource.first.username=dbuser
4app.datasource.first.password=dbpass
5# Hikari数据源的特殊属性
6app.datasource.first.configuration.maximum-pool-size=30
7
8# 配置第二个数据源
9app.datasource.second.url=jdbc:mysql://localhost/second
10app.datasource.second.username=dbuser
11app.datasource.second.password=dbpass
12app.datasource.second.max-total=30
13
如果您将Spring Boot应用程序部署到应用服务器(如Jboss),则可能需要使用其内置功能来配置和管理数据源,并使用JNDI对其进行访问。
spring.datasource.jndi-name
属性可以替代spring.datasource.url,spring.datasource.username和spring.datasource.password属性,以从特定的 JNDI 位置访问DataSource。
例如,application.properties中的以下部分显示了如何访问JBoss定义的DataSource:
21spring.datasource.jndi-name=java:jboss/datasources/customers
2
SpringBoot可以自动配置嵌入式H2,HSQL和Derby数据库,且只需要引入对应依赖即可(无需连接URL、用户名、密码)。
61<dependency>
2 <groupId>org.hsqldb</groupId>
3 <artifactId>hsqldb</artifactId>
4 <scope>runtime</scope>
5</dependency>
6
注意:
设置spring.datasource.generate-unique-name属性为true,可以确保测试所使用的每个上下文都有一个单独的嵌入式数据库。
spring-boot-starter-data-jpa启动器仅是将嵌入式数据库暂时拉入,你需要spring-jdbc才能自动配置。
如果自定义嵌入式数据库的连接URL,请确保禁用了数据库的自动关闭功能,而由Spring来进行控制何时关闭。
SpringBoot在启动时自动加载CLASSPATH根路径下的schema.sql
和data.sql
文件,使用默认数据源初始化数据库。
如果设置了spring.datasource.platform
属性(如hsqldb、h2、oracle、mysql、postgresql等),则会加载对应平台的初始化文件,如schema-mysql.sql
和data-mysql.sql
等。
注意:默认情况下,如果初始化错误,则程序将无法启动,你可以通过spring.datasource.continue-on-error属性来修改它。
Redis提供了丰富的键值缓存和消息代理等功能,SpringBoot为其Lettuce和Jedis客户端提供了基本的自动配置,只需引入spring-boot-starter-data-redis
启动器即可。
171<dependency>
2 <!--引入Redis场景启动器-->
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-data-redis</artifactId>
5 <exclusions>
6 <!--排除lettuce客户端-->
7 <exclusion>
8 <groupId>io.lettuce</groupId>
9 <artifactId>lettuce-core</artifactId>
10 </exclusion>
11 </exclusions>
12</dependency>
13<!--使用Jedis客户端-->
14<dependency>
15 <groupId>redis.clients</groupId>
16 <artifactId>jedis</artifactId>
17</dependency>
需要使用时直接注入RedisConnectionFactory
或StringRedisTemplate
等类型的示例即可。如果需要自定义一些高级配置,可以分别实现JedisClientConfigurationBuilderCustomizer或LettuceClientConfigurationBuilderCustomizer接口。
91
2public class MyBean {
3 private StringRedisTemplate template;
4
5
6 public MyBean(StringRedisTemplate template) {
7 this.template = template;
8 }
9}
SpringBootTest将spring-test与Junit、Mockito等主流测试框架进行了整合及自动配置,并提供了一系列的切片测试注解,简化了SpringBoot程序的测试。
引入启动器
161<!--SpringBootTest启动器,在低版本自动引入Junit5,高版本自动引入Junit5,版本号由SpringBoot父工程版本决定-->
2<dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-test</artifactId>
5 <scope>test</scope>
6</dependency>
7
8<!-- Junit4依赖(仅在高版本SpringBootTest中使用Junit4时需要) -->
9<!--
10<dependency>
11 <groupId>junit</groupId>
12 <artifactId>junit</artifactId>
13 <version>4.12</version>
14 <scope>test</scope>
15</dependency>
16-->
编写业务类
71
2public class UserService {
3 public void doService() {
4 System.out.println("-------- Service --------");
5 }
6}
7
编写测试类
121SpringRunner.class) // 整合Junit4(如果使用Junit5,可以省略@ExtendWith) (
2classes = MyApplication.class) // 引入上下文配置,类似于@ContextConfiguration (
3public class UserServiceTest {
4
5 private UserService userService;
6
7
8 public void test01() {
9 userService.doService();
10 }
11}
12
针对特定场景的测试,只需要加载相对应的Bean即可,SpringBootTest为此提供了许多基于特定场景的测试配置注解,如@JdbcTest、@JsonTest、@DataRedistest、@WebMvcTest等。
SpringBoot使用ServletWebServerApplicationContext
作为嵌入式Servlet容器的上下文实现类,它是WebApplicationContext的一种特殊类型,通过搜索ServletWebServerFactory
来进行自我引导。
ServletWebServerFactory根据不同的Servlet容器分为TomcatServletWebServerFactory
、JettyServletWebServerFactory
或UndertowServletWebServerFactory
,这些都会被自动配置。
提示:具体整合案例请参考快速入门章节!
Springboot自动配置DispatcherServlet组件,默认Servlet上下文根路径为/
,可通过spring.mvc.servlet.path=/acme
属性进行修改。
如果特别需要,也可以定义自己的DispatcherServlet,但是必须提供DispatcherServletPath
指明Servlet上下文根路径。
SpringBoot将会视情况对如下一些视图解析器进行自动配置:
ContentNegotiatingViewResolver
主视图解析器,也叫内容协商视图解析器,Bean名称为viewResolver,仅当存在其它视图解析器时才会被创建,其参考Accept请求头来委派给其它视图解析器。
InternalResourceViewResolver
默认视图解析器,Bean名称为defaultViewResolver,可以用来解析静态资源和JSP页面等,常用的配置有spring.mvc.view.prefix和spring.mvc.view.suffix,默认都为空。
BeanNameViewResolver
Bean名称为beanNameViewResolver,主要在视图解析器链中使用,用于拾取与要解析的View同名的所有Bean。
ThymeleafViewResolver
用于解析Thymeleaf视图的解析器,Bean名称为thymeleafViewResolver,常用的配置有spring.thymeleaf.prefix和spring.thymeleaf.suffix,默认值分别为classpath:/templates/
和.html
。
FreeMarkerViewResolver
用于解析FreeMarker视图的解析器,Bean名称为freeMarkerViewResolver,常用的配置有spring.freemarker.templateLoaderPath、spring.freemarker.prefix和spring.freemarker.suffix,默认值分别为classpath:/templates/
、空和.ftl
。
GroovyMarkupViewResolver
用于解析Groovy模板的解析器,Bean名称为groovyMarkupViewResolver,常用的配置有spring.groovy.template.prefix和spring.groovy.template.suffix,默认值分别为classpath:/templates/
和.tpl
。
有关视图解析器配置的更多信息,可参考WebMvcAutoConfiguration、ThymeleafAutoConfiguration、FreeMarkerAutoConfiguration和GroovyTemplateAutoConfiguration等。
HttpMessageConverter用来转换HTTP请求和响应,如将对象自动转换为JSON等。你可以通过如下方式来注册HttpMessageConverter:
直接添加HttpMessageConverter
到容器,SpringBoot将会自动拾取向SpringMVC注册,并覆盖同名的默认配置。
也可以通过HttpMessageConverters
同时添加多个HttpMessageConverter到容器。
101
2public class MyConfiguration {
3
4 public HttpMessageConverters customConverters(){
5 HttpMessageConverter<?> additional = ...
6 HttpMessageConverter<?> another = ...
7 return new HttpMessageConverters(additional, another);
8 }
9}
10
继承WebMvcConfigurer,覆盖其configureMessageConverters
或extendMessageConverters
方法。
121
2public class MyMessageConverterConfig {
3
4 public WebMvcConfigurer webMvcConfigurer(){
5 return new WebMvcConfigurer() {
6
7 public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
8 converters.add(new MyHttpMessageConverter());
9 }
10 };
11 }
12}
MessageCodesResolver是一个从绑定错误中生成错误码的策略,用于渲染错误信息。如果您设置了spring.mvc.message-codes-resolver.format
属性值为 PREFIX_ERROR_CODE
或POSTFIX_ERROR_CODE
,Spring Boot将为你创建该策略。
Spring MVC使用WebBindingInitializer来为特定请求初始化WebDataBinder,如果容器中存在自定义的ConfigurableWebBindingInitializer,那么SpringBoot将会优先使用它。
如果希望提供RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
的自定义实例,则可以声明WebMvcRegistrationsAdapter
实例以提供此类组件。
可以在配置类上添加@EnableWebMvc
注解,关闭所有默认的MVC配置。
SpringBoot默认从ClassPath中的/static
、/public
、/resources
、/META-INF/resources
四个目录查找静态资源,可以通过spring.resources.static-locations
属性来进行覆盖。
11spring.static-locations=[classpath:/haha/]
此外,Servlet上下文路径/
始终将会被当为静态资源路径。
提示:
静态资源使用
ResourceHttpRequestHandler
拦截处理,可以重写WebMvcConfigurer.addResourceHandlers方法来修改。如果您的应用程序要包成 jar,请不要使用src/main/webapp目录。虽然此目录是一个通用标准,但它只适用于war打包,如果生成的是一个jar,它将被绝大多数的构建工具所忽略。
默认情况下,请求进来会优先被Controller处理,如果非Controller请求,则会被映射到静态资源处理器,其默认前缀为/**
,该前缀可以通过spring.mvc.static-path-pattern
属性修改:
21spring.mvc.static-path-pattern=/resources/**
2
Spring Boot 会查找静态资源路径下的index.html
文件或 index
模板,如果找到任何一个,则会用作应用程序的欢迎界面。
同理,也会查找静态路径下的favicon.ico
文件,用作程序的页签图标。额外的,如果图标未找到,还会再去查找类路径根目录/
。
注意:修改静态资源前缀后可能导致欢迎页和页面图标失效。
Webjars是一种通过Jar包的形式提供前端资源的协议,SpringBoot默认开启对其的支持。如下引入了jquery的Jar包形式,就可以通过http://localhost:8080/webjars/jquery/3.5.1/jquery.js
进行访问。
51<dependency>
2 <groupId>org.webjars</groupId>
3 <artifactId>jquery</artifactId>
4 <version>3.5.1</version>
5</dependency>
提示:更多webjar可以访问https://www.webjars.org/。
SpringBoot还支持SpringMVC提供的高级资源处理功能,例如静态资源缓存清除或者Webjar的版本无关URL(URL地址自动添加版本号)。
缓存清除可以通过以下属性配置,它实际是为资源URL添加了一个内容哈希,例如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
。
21spring.resources.chain.strategy.content.enabled=true
2spring.resources.chain.strategy.content.paths=/**
SpringBoot提供了一个/error
映射,用来处理所有的错误响应,并且在servlet容器中注册为"全局"的错误页面。
对于浏览器客户端,返回一个whitelabel
错误视图,渲染HTTP状态、异常消息等错误信息。
如果是非浏览器客户端,则将生成类似的JSON响应。
你可以通过定义ErrorController(BasicErrorController)
或ErrorAttributes
来修改此默认行为,或使用常规的SpringMVC功能处理,例如@ExceptionHandler
和@ControllerAdvice
。
如需修改状态码所对应的错误页面,可在静态资源目录(/public
)或模板目录(/templates
)下的error
文件夹中设置,文件名为对应的状态码或系列掩码。
141src
2 +- main
3 +- java
4 | + <source code>
5 +- resources
6 +- public
7 | +- error
8 | | +- 404.html
9 | +- <other public assets>
10 +- templates
11 +- error
12 | +- 5xx.ftl
13 +- <other templates>
14
如果需要更复杂的状态码-错误页面映射,可以实现ErrorViewResolver
接口:
81public class MyErrorViewResolver implements ErrorViewResolver {
2
3 public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
4 // Use the request or status to optionally return a ModelAndView
5 return ...
6 }
7}
8
前端
前端表单必须为multipart/form-data
类型。
51<form action="/upload" method="post" enctype="multipart/form-data">
2 <input type="file" name="file" /><br/>
3 <input type="submit" name="" id="" value="提交" />
4</form>
5
控制器
SpringBoot在SpringMVC的基础上进一步简化了文件上传,将上传的文件抽象为一个MultipartFile
对象。
351 /**
2 * 文件保存在服务器,url地址保存在数据库
3 * 上传成功之后返回成功保存的url地址
4 */
5"/upload") (
6public String upload( MultipartFile file, HttpServletRequest request){
7 if(!file.isEmpty()){
8 String uploadPath = "C:\\uploadFile";
9 // 如果目录不存在则创建
10 File uploadDir = new File(uploadPath);
11 if (!uploadDir.exists()) {
12 uploadDir.mkdir();
13 }
14 String OriginalFilename = file.getOriginalFilename();//获取原文件名
15 String suffixName = OriginalFilename.substring(OriginalFilename.lastIndexOf("."));//获取文件后缀名
16 //重新随机生成名字
17 String filename = UUID.randomUUID().toString() +suffixName;
18 File localFile = new File(uploadPath+"\\"+filename);
19 try {
20 file.transferTo(localFile); //把上传的文件保存至本地
21 /**
22 * 这里应该把filename保存到数据库,供前端访问时使用
23 */
24 return filename;//上传成功,返回保存的文件地址
25 }catch (IOException e){
26 e.printStackTrace();
27 System.out.println("上传失败");
28 return "";
29 }
30 }else{
31 System.out.println("文件为空");
32 return "";
33 }
34}
35
可以使用spring.servlet.multipart
前缀的属性来进行文件上传配置,更多信息可参考MultipartProperties
类。
61#设置单个文件大小
2spring.servlet.multipart.max-file-size= 100MB
3
4#设置单次请求文件的总大小
5spring.servlet.multipart.max-request-size= 100MB
6
SpringBoot默认使用Jackson
来进行序列化和反序列化JSON数据,你可以通过配置ObjectMapper来调整其默认行为,或使用JsonSerializer/JsonDeserializer来自定义某些类的序列化/反序列化逻辑。
SpringBoot创建的ObjectMapper将默认禁用MapperFeature.DEFAULT_VIEW_INCLUSION、DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES和SerializationFeature.WRITE_DATES_AS_TIMESTAMPS选项。
如需对SpringBoot创建的ObjectMapper进行自定义配置,可以通过如下一些属性,这些属性将会被应用于Jackson2ObjectMapperBuilder
,并对其创建的所有ObjectMapper生效。
Enum | Property | Values |
---|---|---|
com.fasterxml.jackson.databind.DeserializationFeature | spring.jackson.deserialization.<feature_name> | true , false |
com.fasterxml.jackson.core.JsonGenerator.Feature | spring.jackson.generator.<feature_name> | true , false |
com.fasterxml.jackson.databind.MapperFeature | spring.jackson.mapper.<feature_name> | true , false |
com.fasterxml.jackson.core.JsonParser.Feature | spring.jackson.parser.<feature_name> | true , false |
com.fasterxml.jackson.databind.SerializationFeature | spring.jackson.serialization.<feature_name> | true , false |
com.fasterxml.jackson.annotation.JsonInclude.Include | spring.jackson.default-property-inclusion | always , non_null , non_absent , non_default , non_empty |
下面是一个通过属性开启格式化输出的示例:
21spring.jackson.serialization.indent_output=true。
2
除此之外,Jackson2ObjectMapperBuilder还可以通过com.fasterxml.jackson.databind.Module或Jackson2ObjectMapperBuilderCustomizer来进行自定义配置。
61
2public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
3 return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
4 .serializers(LOCAL_DATETIME_SERIALIZER);
5}
6
如果需要完全自定义ObjectMapper的配置,可以创建自己的Jackson2ObjectMapperBuilder实例,SpringBoot将会优先使用它。
61
2public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
3 return new Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
4 .serializationInclusion(JsonInclude.Include.NON_NULL);
5}
6
也可以通过@Primary注解,定义一个注入优先级更高ObjectMapper实例来使用。
101
2
3public ObjectMapper objectMapper() {
4 JavaTimeModule module = new JavaTimeModule();
5 module.addSerializer(LOCAL_DATETIME_SERIALIZER);
6 return new ObjectMapper()
7 .setSerializationInclusion(JsonInclude.Include.NON_NULL)
8 .registerModule(module);
9}
10
JsonSerializer
和JsonDeserializer
用来自定义Jackson的序列化和反序列化逻辑,SpringBoot提供了@JsonComponent
注解,可以直接将其注册到Jackson。
该注解可以直接加在JsonSerializer或JsonDeserializer的实现类,或者是它们的外部类上:
151import java.io.*;
2import com.fasterxml.jackson.core.*;
3import com.fasterxml.jackson.databind.*;
4import org.springframework.boot.jackson.*;
5
6
7public class Example {
8 // JsonSerializer
9 public static class Serializer extends JsonSerializer<SomeObject> {
10 }
11 // JsonDeserializer
12 public static class Deserializer extends JsonDeserializer<SomeObject> {
13 }
14}
15
除此之外,Spring Boot还提供了JsonObjectSerializer
和JsonObjectDeserializer
基类,在序列化对象时为标准Jackson版本提供了有用的替代方法,详细说明请参考官方文档。
我们可以创建自己的MappingJackson2HttpMessageConverter
来完全自定义上述Json转换行为。
如果需要向Servlet容器注册原生Servlet
、Filter
和Listener
等组件,可以使用下面两种方式:
从容器中查找:SpringBoot自动扫描容器中的原生Servlet组件,并向Web服务器进行注册(默认的dispatcherType为REQUEST)。
从Classpath扫描:在@Configuration类上添加@ServletComponentScan
注解来扫描指定包下带@WebServlet、@WebFilter或@WebListener注解的Servlet组件,默认扫描当前包。
注意:
如果是Servlet或Filter组件,还可以借助
FilterRegistrationBean
或ServletRegistrationBean
来注册,同时设置一些初始化参数。@ServletComponentScan在独立容器中无效,而是使用该容器的内置发现机制。
如果依赖了DataSource等其它配置,最好是在初次使用时才进行初始化。
默认情况下,如果上下文仅包含一个Servlet,那么将会映射到/
,如果有多个Servlet,那么将会使用其Bean名称作为路径前缀。
对于过滤器,将会始终映射到/*
。SpringBoot为多种场景所使用的过滤器做了自动配置,下面是一个清单:
Servlet Filter | Order |
---|---|
OrderedCharacterEncodingFilter | Ordered.HIGHEST_PRECEDENC |
WebMvcMetricsFilter | Ordered.HIGHEST_PRECEDENCE + 1 |
ErrorPageFilter | Ordered.HIGHEST_PRECEDENCE + 1 |
HttpTraceFilter | Ordered.LOWEST_PRECEDENCE - 10 |
提示:这些映射规则可以通过
ServletRegistrationBean
、FilterRegistrationBean
和ServletListenerRegistrationBean
来完全控制。
如果不想容器中的某个组件向Web服务器注册,则必须显式声明禁止注册。
71
2public FilterRegistrationBean registration(MyFilter filter) {
3 FilterRegistrationBean registration = new FilterRegistrationBean(filter);
4 registration.setEnabled(false);
5 return registration;
6}
7
跨域资源共享(Cross-origin resource sharing,CORS)是大多数浏览器实现的一个W3C规范,其可允许您以灵活的方式指定何种跨域请求可以被授权,而不是使用一些不太安全和不太强大的方式(比如IFRAME或者JSONP)。
您可在SpringBoot应用程序中使用@CrossOrigin
注解配置控制器方法启用CORS,或通过重写WebMvcConfigurer的addCorsMappings(CorsRegistry)
方法来定义全局CORS配置:
131
2public class MyConfiguration {
3
4 public WebMvcConfigurer corsConfigurer() {
5 return new WebMvcConfigurer() {
6
7 public void addCorsMappings(CorsRegistry registry) {
8 registry.addMapping("/api/**");
9 }
10 };
11 }
12}
13
SpringBoot为FreeMarker、Thymeleaf、Groovy、Mustache、JSP等模板技术提供了自动配置(对应的视图解析器等),默认从src/main/resources/templates
目录查找模板文件。
注意:尽量不要使用JSP作为SpringBoot的模板引擎,它和嵌入式容器一起使用时会有一些问题。
SpringMVC通过解析请求路径将请求映射到不同的控制器方法,但SpringBoot默认禁用了其后缀模式匹配。这意味着GET /projects/spring-boot.json
之类的请求将不会与@GetMapping("/projects/spring-boot")
所注解的方法相匹配,因为如今基于Accept请求头的内容协商已变得非常可靠。
除此之外,你也可以通过URL参数的形式附带内容信息,如GET /projects/spring-boot?format=json
,开启该功能的配置如下:
61# 开启使用URL参数进行内容协商
2spring.mvc.contentnegotiation.favor-parameter=true
3
4# URL参数名默认为format,可以通过下面属性修改:
5spring.mvc.contentnegotiation.parameter-name=myparam
6
如果你了解所有注意事项后,仍然希望开启后缀模式匹配,可以使用下面配置:
121# 方式一:开启所有后缀模式匹配
2spring.mvc.contentnegotiation.favor-path-extension=true
3spring.mvc.pathmatch.use-suffix-pattern=true
4
5# 方式二:仅开启手动注册的后缀模式匹配
6spring.mvc.contentnegotiation.favor-path-extension=true
7spring.mvc.pathmatch.use-registered-suffix-pattern=true
8
9# 手动注册后缀类型如下:
10spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc
11spring.mvc.contentnegotiation.media-types.markdown=text/markdown
12
RestTemplate可能需要自定义一些应用配置,所以SpringBoot并未提供具体的RestTemplate实例。你可以注入RestTemplateBuilder来快速创建和配置所需的RestTemplate,并会自动应用HttpMessageConverters。
151
2public class MyService {
3 private final RestTemplate restTemplate;
4
5
6 public MyService(RestTemplateBuilder builder) {
7 // 创建一个RestTemplate实例,并添加BASIC身份验证支持
8 this.restTemplate = builder.basicAuthentication("user", "password").build()
9 }
10
11 public Details someRestCall(String name) {
12 return this.restTemplate.getForObject("/{name}/details", Details.class, name);
13 }
14
15}
如果RestTemplateBuilder的配置项不能满足你的需求,还可以实现RestTemplateCustomizer接口,它将应用于所有通过RestTemplateBuilder创建的RestTemplate。
191// 为除192.168.0.5之外的所有主机配置代理
2static class ProxyCustomizer implements RestTemplateCustomizer {
3
4 public void customize(RestTemplate restTemplate) {
5 HttpHost proxy = new HttpHost("proxy.example.com");
6 HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(
7 new DefaultProxyRoutePlanner(proxy) {
8
9 public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
10 if (target.getHostName().equals("192.168.0.5")) {
11 return null;
12 }
13 return super.determineProxy(target, request, context);
14 }
15
16 }).build();
17 restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
18 }
19}
注意:你也可以创建自己的RestTemplateBuilder来实现更多配置,但此时RestTemplateCustomizer将不会被自动注册。
Spring提供了三个JSON库的默认配置:Jackson(默认)、Gson、JSON-B,当类路径下存在对应的Jar包时,将会开启使用。
SpringBoot中通过@EnableAsync
注解开启异步任务支持:
91
2// 开启异步任务支持
3public class MyApplication {
4 public static void main(String[] args) {
5 SpringApplication springApplication = new SpringApplication(MyApplication.class);
6 ConfigurableApplicationContext context = springApplication.run(args);
7 }
8}
9
通过@Async
注解标记方法为异步方法:
141
2public class AsyncService {
3
4
5 public void doHello() {
6 try {
7 Thread.sleep(3000);
8 } catch (InterruptedException e) {
9 e.printStackTrace();
10 }
11 System.out.println("doHello...");
12 }
13}
14
当该方法被Spring创建的代理类对象调用时,就会异步执行。
SpringBoot Actuator可以方便的监视和管理你的生产应用程序,并自动配置审计、运行状况、Metrics收集等。
81<!--引入spring-boot-starter-actuator启动器,开启生产监视功能-->
2<dependencies>
3 <dependency>
4 <groupId>org.springframework.boot</groupId>
5 <artifactId>spring-boot-starter-actuator</artifactId>
6 </dependency>
7</dependencies>
8
EndPoint(端点)是Actuator与生产应用程序的交互点。例如,获取应用程序基本运行状况信息可通过health端点。
SpringBoot提供了许多内置端点,其中一些与特定技术无关的端点如下所示:
端点ID | 说明 |
---|---|
auditevents | 公开当前应用程序的审核事件信息 |
beans | 显示应用程序中所有SpringBean的完整列表 |
caches | 公开可用的缓存 |
conditions | 显示在配置和自动配置类上评估的条件以及它们匹配或不匹配的原因 |
configprops | 显示所有@ConfigurationProperties的整理列表 |
env | 从Spring的ConfigurableEnvironment公开属性 |
flyway | 显示已应用的所有Flyway数据库迁移 |
health | 显示应用程序运行状况信息 |
httptrace | 显示HTTP跟踪信息(默认情况下,最近100个HTTP请求-响应交换) |
info | 显示任意应用程序信息 |
integrationgraph | 显示Spring Integration图 |
loggers | 显示和修改应用程序中Logger的配置 |
liquibase | 显示已应用的所有Liquibase数据库迁移 |
metrics | 显示当前应用程序的“Metrics”信息 |
mappings | 显示所有@RequestMapping路径的整理列表 |
scheduledtasks | 显示应用程序中的计划任务。 |
sessions | 允许从Spring Session支持的会话存储中检索和删除用户会话(不适用WebFlux)。 |
shutdown | 使应用程序正常关闭 |
threaddump | 执行线程转储 |
如果是Web应用程序(Spring MVC/Spring WebFlux/Jersey),则还提供以下附加端点:
端点ID | 说明 |
---|---|
heapdump | 返回一个hprof堆转储文件。 |
jolokia | 通过HTTP公开JMX bean(当 Jolokia在Classpath上时,不适用于WebFlux)。 |
logfile | 返回日志文件的内容(如果已设置logging.file或logging.path属性)。支持使用 HTTP Range Headers 来检索部分日志文件的内容。 |
prometheus | 以Prometheus服务器可以抓取的格式公开Metrics。 |
提示:关于EndPoint的更多信息以及EndPoint的请求和响应格式,请参阅单独的API文档。
health端点简介
health端点公开了程序基本的运行状况信息,监视软件一般通过它来判断系统是否发生故障。这些运行状况信息由上下文中的HealthIndicator(健康指示器)
收集,然后由HealthAggregator
根据状态的有序列表进行排序,选择列表中的第一个状态为整体运行状态,如果不存在,则使用UNKNOWN状态。
management.endpoint.health.show-details
属性可以设置健康状态明细信息向哪些角色展示,可选的值有never(默认值,始终不展示明细)
、always(始终展示明细)
、when-authorized(仅展示给授权角色)
。授权角色通过management.endpoint.health.roles
属性进行配置,如果为空(默认),则所有通过身份验证的角色都被视为已授权。
提示:
HealthIndicatorRegistry支持在运行时注册和注销运行状况指示器。
如果您已保护应用程序安全并希望使用always,则安全配置必须允许经过身份验证的用户和未经身份验证的用户都可以访问运行状况端点。
内置健康指示器
在满足特定的条件时,SpringBoot会对下面一些健康指示器(HealthIndicators)进行自动配置。
Name | Description |
---|---|
CassandraHealthIndicator | 检查Cassandra数据库是否已启动 |
CouchbaseHealthIndicator | 检查Couchbase群集是否已启动 |
DiskSpaceHealthIndicator | 检查磁盘空间是否不足 |
DataSourceHealthIndicator | 检查是否可以创建DataSource的连接 |
ElasticsearchHealthIndicator | 检查Elasticsearch集群是否已启动 |
InfluxDbHealthIndicator | 检查InfluxDB服务器是否已启动 |
JmsHealthIndicator | 检查JMS代理是否启动 |
MailHealthIndicator | 检查邮件服务器是否已启动 |
MongoHealthIndicator | 检查Mongo数据库是否已启动 |
Neo4jHealthIndicator | 检查Neo4j服务器是否已启动 |
RabbitHealthIndicator | 检查Rabbit服务器是否已启动 |
RedisHealthIndicator | 检查Redis服务器是否启动 |
SolrHealthIndicator | 检查Solr服务器是否已启动 |
提示:
management.health.defaults.enabled
属性可以将上述指示器全部禁用。
自定义健康指示器
可以通过实现HealthIndicator接口来自定义健康指示器,标识符默认为不带HealthIndicator后缀的Bean名称。
221import org.springframework.boot.actuate.health.Health;
2import org.springframework.boot.actuate.health.HealthIndicator;
3import org.springframework.stereotype.Component;
4
5// 自定义健康指示器,标识符为 my
6
7public class MyHealthIndicator implements HealthIndicator {
8
9
10 public Health health() {
11 // 自定义检查
12 int errorCode = check();
13 if (errorCode != 0) {
14 // 检查失败
15 return Health.down().withDetail("Error Code", errorCode).build();
16 }
17
18 // 检查OK
19 return Health.up().build();
20 }
21}
22
一般来说,都会为健康指示器的返回值设置健康状态,内置的健康状态有如下一些:
Status | Mapping |
---|---|
DOWN | SERVICE_UNAVAILABLE(503) |
OUT_OF_SERVICE | SERVICE_UNAVAILABLE(503) |
UP | 默认情况下没有Map,http 状态为 200 |
UNKNOWN | 默认情况下没有Map,http 状态为 200 |
提示:
如需自定义其它健康状态(如FATAL)或修改HTTP响应状态码,请参考官方文档!
更多详细的控制可使用HealthStatusHttpMapper类。
info端点简介
info端点公开了程序上下文中InfoContributor(信息贡献者)
所收集的各种信息。
内置信息贡献者
在满足特定的条件时,SpringBoot会对下面一些信息贡献者(InfoContributor)进行自动配置。
Name | Description |
---|---|
EnvironmentInfoContributor | 公开Environment中的任何key |
GitInfoContributor | 如果git.properties文件可用,则公开git信息git.branch/git.commit.id/git.commit.time |
BuildInfoContributor | 如果META-INF/build-info.properties文件可用,则公开构建信息 |
提示:
info.*
属性可以自定义info信息的显示,如info.app.encoding=UTF-8。
management.info.git.mode=full
属性可以显示完整的git信息,即git.properties的完整内容。
management.info.defaults.enabled
属性可以将上述贡献者全部禁用。
自定义信息贡献者
可以通过实现InfoContributor接口来自定义信息贡献者。
151import java.util.Collections;
2
3import org.springframework.boot.actuate.info.Info;
4import org.springframework.boot.actuate.info.InfoContributor;
5import org.springframework.stereotype.Component;
6
7
8public class ExampleInfoContributor implements InfoContributor {
9
10
11 public void contribute(Info.Builder builder) {
12 builder.withDetail("example01", Collections.singletonMap("key01", "value01"));
13 }
14}
15
如果到达info端点,则应该看到包含以下附加条目的响应:
51{
2 "example01": {
3 "key01" : "value01"
4 }
5}
loggers端点可以在运行时查看和配置应用程序的日志级别。如通过/loggers
路径查看所有的日志级别,通过/loggers/root
路径查看root logger的日志级别信息。
51{
2 "configuredLevel":"INFO",
3 "effectiveLevel":"INFO"
4}
5
要修改为指定的日志级别,请使用POST方式并附带请求体参数,如下修改root logger的日志级别为DEBUG。
41/loggers/root
2{
3 "configuredLevel": "DEBUG"
4}
提示:日志级别可以是TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF、null(没有显式配置)等。
httptrace端点将会跟踪最近100次请求-响应交换的基本信息,并存储到InMemoryHttpTraceRepository
中,其基本配置可通过management.trace.http.include
属性来调整。
如需进行高级的定义,请定义自己的HttpExchangeTracer、InMemoryHttpTraceRepository或HttpTraceRepository实现。
默认情况下,除shutdown
之外的所有端点都处于启用状态,如需启用或禁用某个端点,可以设置其enabled
属性。
21# 启用shutdown端点
2management.endpoint.shutdown.enabled=true
如需批量设置,可以通过management.endpoints.enabled-by-default
修改端点是否启用的默认值。
31# 禁用所有端点,再单独开启info端点
2management.endpoints.enabled-by-default=false
3management.endpoint.info.enabled=true
注意:禁用的端点将从应用程序中完全删除,如果您只想修改端点是否公开,请使用参考下一小节。
端点只有公开后才能被访问,如需公开或关闭某个端点,请使用下面特定于公开方式的include
和exclude
属性:
属性 | 默认值 | 说明 |
---|---|---|
management.endpoints.jmx.exposure.exclude | JMX方式关闭的端点 | |
management.endpoints.jmx.exposure.include | * | JMX方式公开的端点 |
management.endpoints.web.exposure.exclude | HTTP方式关闭的端点 | |
management.endpoints.web.exposure.include | info, health | HTTP方式公开的端点 |
下面一些使用案例:
61# 修改JMX方式仅公开health和info端点
2management.endpoints.jmx.exposure.include=health,info
3
4# 修改HTTP方式公开除env和beans之外的所有端点(注意:*在YML中具有特殊含义,使用时请添加引号include: "*")
5management.endpoints.web.exposure.include=*
6management.endpoints.web.exposure.exclude=env,beans
提示:如需更加精细的控制端点的公开时间,可以继承
EndpointFilter
接口来进行扩展。
访问路径和端口
HTTP端点的访问路径由前缀+端点映射路径
组成,前缀默认为/actuator
,端点映射路径默认为端点id
。 例如health端点默认通过/actuator/health进行访问。
91# 修改前缀,修改后通过 /manage/health 访问health端点
2management.endpoints.web.base-path=/manage
3
4# 修改端点映射路径,修改后通过 /前缀/healthcheck 访问health端点
5management.endpoints.web.path-mapping.health=healthcheck
6
7# 修改访问端口
8management.server.port=8081
9
注意:前缀是相对于
server.servlet.context-path
的,但如果配置了management.server.port
,则相对于management.server.servlet.context-path
。
来源地址
41# 配置自定义端口,并设置仅本地(127.0.0.1)可访问管理服务器
2management.server.port=8081
3management.server.address=127.0.0.1
4
注意:仅当端口与主服务器端口不同时,您才能在其他地址上侦听!
设置SSL
默认情况下,管理服务器与主应用程序使用相同的SSL配置,但如果自定义了管理服务器端口,则可以分别进行配置。
161# 主应用程序端口和SSL配置(通过HTTPS访问)
2server.port=8443
3server.ssl.enabled=true
4server.ssl.key-store=classpath:main.jks
5server.ssl.key-password=secret
6
7# 自定义管理服务器端口,并单独禁用SSL(通过HTTP访问)
8# management.server.port=8080
9# management.server.ssl.enabled=false
10
11# 自定义管理服务器端口,并设置单独的SSL
12management.server.port=8080
13management.server.ssl.enabled=true
14management.server.ssl.key-store=classpath:management.jks
15management.server.ssl.key-password=secret
16
Security配置
由于端点暴露信息的敏感性,你应该像其它敏感URL一样,保护HTTP端点的安全。如果存在Spring Security,则默认使用其内容协商策略保护端点,典型的配置如下:
121
2public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
3
4 protected void configure(HttpSecurity http) throws Exception {
5 http.requestMatcher(EndpointRequest.toAnyEndpoint()) // 匹配任何端点
6 .authorizeRequests()
7 .anyRequest()
8 .hasRole("ENDPOINT_ADMIN") // 仅支持ENDPOINT_ADMIN角色访问
9 .and()
10 .httpBasic();
11 }
12}
如果允许未经身份验证的端点访问,可以配置如下:
111
2public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
3
4
5 protected void configure(HttpSecurity http) throws Exception {
6 http.requestMatcher(EndpointRequest.toAnyEndpoint()) // 匹配任何端点
7 .authorizeRequests()
8 .anyRequest()
9 .permitAll();
10 }
11}
CROS支持
如果使用Spring MVC或Spring WebFlux,可以通过下面方式支持HTTP端点的CROS。
31# 允许来自example.com域的GET和POST调用
2management.endpoints.web.cors.allowed-origins=http://example.com
3management.endpoints.web.cors.allowed-methods=GET,POST
有关选项的完整列表,请参见CorsEndpointProperties
。
禁用HTTP方式访问
如果您不想通过HTTP方式公开端点,则可以将Management端口设置为-1:
31# 禁用HTTP方式访问管理服务器
2management.server.port=-1
3
或使用management.endpoints.web.exposure.exclude
属性关闭所有HTTP端点:
21# 所有HTTP端点都不暴露
2management.endpoints.web.exposure.exclude=*
MBean名称
MBean名称由端点id
生成,例如health端点公开为org.springframework.boot:type=Endpoint,name=Health。但是,当应用程序包含多个ApplicationContext时,可能会出现名称冲突,可通过下面属性生成唯一的MBean名称。
31# MBean生成唯一名称
2spring.jmx.unique-names=true
3
暴露的JMX域
默认情况下,SpringBoot将Management端点暴露在org.springframework.boot
域下,可通过下面属性进行修改。
31# 暴露端点的JMX域
2management.endpoints.jmx.domain=com.huangyuanxin.notes.springboot
3
转换为HTTP端点
Jolokia(JMX-HTTP bridge)可以让你以HTTP方式访问JMX Bean。首先导入依赖如下:
51<dependency>
2 <groupId>org.jolokia</groupId>
3 <artifactId>jolokia-core</artifactId>
4</dependency>
5
再通过management.endpoints.web.exposure.include=jolokia
来暴露Jolokia端点,然后就可以通过/actuator/jolokia来访问它。
注意:
可以通过servlet参数或
management.endpoint.jolokia.config.xxx
属性来配置Jolokia,例如management.endpoint.jolokia.config.debug=true。如果您使用Jolokia但不希望Spring Boot对其进行配置,需将management.endpoint.jolokia.enabled属性设置为false。
禁用JMX方式访问
31# 关闭所有JMX端点
2management.endpoints.jmx.exposure.exclude=*
3
如果属性名以password
、secret
、key
或token
结尾,则SpringBoot在返回相关端点信息时,会将其值自动替换为******
,防止部分端点(如env
和configprops
)泄露密码等敏感信息。
如需修改此行为,可以通过management.endpoint.env.keys-to-sanitize
或management.endpoint.configprops.keys-to-sanitize
属性设置需要过滤的Key(支持正则表达式)。
使用@Endpoint
注解可以将Bean声明为一个端点,Bean中被@ReadOperation
、@WriteOperatio
或@DeleteOperation
注解的方法将通过HTTP或JMX进行公开。
201import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
2import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
3import org.springframework.context.annotation.Configuration;
4
5import java.util.HashMap;
6import java.util.Map;
7
8
9id = "testEndpoint") (
10public class WebEndpointTest {
11
12
13 public Map<String, String> test() {
14 Map<String, String> result = new HashMap<String, String>();
15 result.put("name", "hello");
16 result.put("age", "18");
17 return result;
18 }
19}
20
在端点被公开后(management.endpoints.web.exposure.include=*),即可通过/actuator/testEndpoint
或JMX方式进行访问。
注意:
如果仅需通过HTTP或JMX方式中的一种进行公开,可以使用特定的注解
@WebEndpoint
或@JmxEndpoint
与之相关的还有
@EndpointWebExtension
和@EndpointJmxExtension
注解也用于端点的扩展。
端点支持接收简单类型的参数,HTTP端点通过URL查询参数或JSON格式的请求体参数传入,JMX端点通过MBean传入。如JSON格式的请求体参数示例如下:
41{
2 "name": "test",
3 "counter": 42
4}
对于Web端点,还可使用@Selector
注解方法参数,将其标识为路径变量,效果与Spring MVC的@PathVariable注解类似。
注意:
参数映射要求开启Java的
-parameters
编译参数,如果使用了SpringBoot父工程和Maven插件,将会自动开启。如果类型不匹配,将会使用
ApplicationConversionService
实例进行类型转换,转换失败则响应400(错误请求)。默认情况下,端点参数都是必选项,可以通过
@org.springframework.lang.Nullable
注解是其变为可选。
Spring MVC/Spring WebFlux/Jersey框架会自动公开@Endpoint
、@WebEndpoint
或@EndpointWebExtension
上的Operation,每个Operation都将生成特定的请求谓词。
谓词的路径:默认为端点基本路径(/actuator)+端点ID,例如ID为Sessions的端点将使用/actuator/sessions作为其谓词路径。
谓词的HTTP请求类型:由Operation类型决定,@ReadOperation为GET、@WriteOperation为POST、@DeleteOperation为DELETE方式。
Web端点的响应状态:取决于Operation类型以及该Operation是否返回值(针对非void操作)。
对于@ReadOperation
,在返回值时,响应状态将为200,如果未返回值,则响应状态将为404(未发现)。
对于@WriteOperation
或@DeleteOperation
,在返回值时,响应状态为200,如果未返回值,则响应状态将为204(无内容)。
@WebEndpoint
或@EndpointWebExtension
可以接收当前的java.security.Principal
或org.springframework.boot.actuate.endpoint.SecurityContext
作为方法参数。前者通常与@Nullable结合使用,以为经过身份验证和未经身份验证的用户提供不同的行为。后者通常用于使用其isUserInRole(String)方法执行授权检查。
提示:有关Consumes、Produces、Web端点范围请求等更多信息可参考官方文档。
@ServletEndpoint
可以将Servlet公开为端点,但其与Servlet容器深度集成,可移植性差,对于新端点,应尽可能使用@Endpoint和@WebEndpoint注解。
@ControllerEndpoint
和@RestControllerEndpoint
用于公开特定于Spring Web框架的端点,其使用GetMapping、@PostMapping、@DeleteMapping、@RequestMapping等Spring MVC/Spring WebFlux的标准注解进行方法和参数的映射。
101
2id = "user") (
3public class UserEndpointController {
4 "getUser") (
5 public String getUser() {
6 return "I am admin";
7 }
8}
9
10// 访问地址:http://localhost:9002/actuator/user/getUser
注意:
@RestControllerEndpoint不会注册Bean,仍需要添加@Component注解。
Controller端点提供了与Spring Web框架的更深层集成,但可移植性变差。因此,尽可能使用@Endpoint和@WebEndpoint注解。
Micrometer是Java平台上的一种通用应用程序指标接口,类似于日志体系中的SLF4J,它提供了Timers、Guauges、Counters等多种度量指标类型,并支持Elastic、Influx、JMX、Prometheus等众多的监视系统。
Micrometer中有两个最核心的概念,分别是计量器(Meter)和计量器注册表(MeterRegistry)。其中计量器用来收集不同类型的性能指标信息,Micrometer提供了如下几种不同类型的计量器:
计数器(Counter):表示收集的数据是按照某个趋势(增加/减少)一直变化的,也是最常用的一种计量器,例如接口请求总数、请求错误总数、队列数量变化等。
计量仪(Gauge):表示搜集的瞬时的数据,可以任意变化的,例如CPU负载、Mem使用量、Network使用量、实时在线人数统计等。
计时器(Timer):用来记录事件的持续时间,这个用的比较少。
分布概要(Distribution summary):用来记录事件的分布情况,表示一段时间范围内对数据进行采样,可以用于统计网络请求平均延迟、请求延迟占比等。
SpringBoot Actuator内置了Micrometer依赖,并自动配置CompositeMeterRegistry
,查找类路径下支持的计量器注册表(MeterRegistry),这些计量器注册表由micrometer-registry-Xxxx依赖引入。
61 <!--集成prometheus-->
2 <dependency>
3 <groupId>io.micrometer</groupId>
4 <artifactId>micrometer-registry-prometheus</artifactId>
5 <version>1.1.4</version>
6 </dependency>
下面是一些相关的属性配置:
61# 禁用类路径下的某个计量器注册表,如Datadog
2management.metrics.export.datadog.enabled=false
3
4# 禁止添加到Metrics类的全局静态CompositeMeterRegistry,默认为true
5management.metrics.use-global-registry=false
6
您可以注册任意数量的MeterRegistryCustomizer
来进一步配置计量器注册表,例如在向计量器注册表注册任何计量器之前应用通用标签(tag):
111
2MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
3 return registry -> registry.config().commonTags("region", "us-east-1");
4}
5
6
7// MeterRegistryCustomizer配置支持泛型兼容
8
9MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
10 return registry -> registry.config().namingConvention(MY_CUSTOM_CONVENTION);
11}
完成计量器注册表配置后,可以通过注入的方式获取计量器注册表并注册计量器,如下注册一个 Counter 类型的计量器统计core接口的访问次数。
281
2"/v1") (
3public class IndexController {
4
5 MeterRegistry registry;
6
7 // 计量器引用
8 private Counter counter_core;
9
10
11 private void init(){
12 // 注册一个 Counter 类型的计量器
13 counter_core = registry.counter("app_requests_method_count", "method", "IndexController.core");
14 }
15
16 value = "/core") (
17 public Object coreUrl(){
18 try{
19 // 计量器+1
20 counter_core.increment();
21 } catch (Exception e) {
22 return e;
23 }
24 return counter_core.count() + " coreUrl Monitor by Prometheus.";
25 }
26}
27
28
提示:可以通过MeterBinder来向Spring管理的MeterRegistry自动注册Metrics。
SpringBoot Actuator支持将指标数据导出到众多的监视系统,如导出到本地的Elastic,配置如下:
21management.metrics.export.elastic.host=http://elastic.example.com:8086
2
或者通过提供/actuator/prometheus端点(默认关闭)的方式让Prometheus主动获取监控数据:
61scrape_configs
2job_name'spring'
3 metrics_path'/actuator/prometheus'
4 static_configs
5targets'HOST:PORT'
6
更多监视系统配置请参考相应的官方文档!
SpringBoot将根据当前环境配置如下一些核心Metrics:
JVM Metrics(包括各种内存和缓冲池、与垃圾收集有关的统计数据、Threads utilization、加载/卸载的类数等)
CPU Metrics
文件描述符
Kafka Metrics
Log4j2 Metrics(记录每个级别记录到Log4j2的事件数)
Logback Metrics(记录每个级别记录到Logback的事件数)
运行时间 Metrics(程序正常运行时间和程序绝对启动时间)
Tomcat Metrics
Spring Integration Metrics
SpringMVC Metrics
数据源 Metrics
缓存 Metrics
......
指标属性
211# 通用标签(通常用于在操作环境(如主机,实例,区域,堆栈等)上进行维度深入分析,适用于所有监视系统)
2# 将region和stack标签添加到所有监视系统
3management.metrics.tags.region=us-east-1
4management.metrics.tags.stack=prod
5
6# 禁用所有ID以example.remote开头的指标
7management.metrics.enable.example.remote=false
8
9# 是否发布适合计算可凝集(跨维度)百分位数逼近的直方图
10# management.metrics.distribution.percentiles-histogram
11
12# 通过限制期望值的范围来发布较少的直方图桶
13# management.metrics.distribution.minimum-expected-value
14# management.metrics.distribution.maximum-expected-value
15
16# 发布在应用程序中计算的百分位值
17management.metrics.distribution.percentiles
18
19# 发布包含您的 SLA 定义的存储区的累积直方图
20management.metrics.distribution.sla
21
注意:如果使用Graphite,则通用标签的顺序很重要,由于使用这种方法不能保证通用标签的顺序,因此建议Graphite用户定义自定义MeterFilter。
MeterFilter
可以通过io.micrometer.core.instrument.config.MeterFilter
接口配置Meter,如将所有ID以com.example开头的Meter的mytag.region标签重命名为mytag.area:
51
2public MeterFilter renameRegionTagMeterFilter() {
3 return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
4}
5
Metrics端点可用于诊断检查应用程序收集的Metrics,如/actuator/metrics将显示可用监视系统的名称列表,/actuator/metrics/jvm.memory.max将显示JMX监视器的信息。
如果需要更加深入的了解相应的监视信息,可以通过tag=KEY:VALUE
形式的查询参数,如/actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace。
Spring Boot Developer Tools在开发阶段提供了一些额外的功能,如默认属性、全局配置、自动重启、远程调试和更新等,解决开发中的一些繁琐问题。如果需要使用,可以通过如下依赖来引入:
71 <dependencies>
2 <dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-devtools</artifactId>
5 <optional>true</optional>
6 </dependency>
7 </dependencies>
注意:开发者工具仅适用于开发或测试环境,当使用java -jar 命令启动,或使用特殊的类加载器启动时被视为“完全打包”的应用程序,开发者工具将会被移除。
开发者工具修改了一些默认属性,使其更适用于开发和测试环境,如通过在application.properties中添加配置spring.thymeleaf.cache=false为thymeleaf禁用默认的缓存等。
提示:
开发者工具的所有默认属性可在DevToolsPropertyDefaultsPostProcessor查找。
如果想禁用默认属性,可配置
spring.devtools.add-properties
属性为false。
开发者工具会自动扫描HOME
目录下的.spring-boot-devtools.properties
文件,读取其中的全局配置,并且优先采用。
注意:如果是windows用户,可能需要设置一个环境变量HOME。
开发者工具为应用创建两个类加载器,分别是加载不变类(例如来自第三方jar的类)的基础类加载器和加载可变类(当前正在开发的类)的重启类加载器。当classpath上有文件被修改时,程序将自动重启,并创建新的重启类加载器。这种方式相较于应用平时使用的“冷启动”要快得多,毕竟基础类加载器已经处于可用的状态。关于详细配置请参考官方文档!
提示:如果想体验更加强大的"热部署"功能,推荐使用商业软件Jrebel。
开发者工具支持远程调试功能,详细配置请参考官方文档!
Spring Initializer是一个创建SpringBoot项目的快速向导,它根据用户所选择的场景,自动引入对应的场景启动器,并进行一些基础配置。
Spring Boot CLI 是一个命令行工具,用于运行Groovy脚本,快速开发SpringBoot应用程序。更多资料请参考官方文档!
SpringBoot Maven Plugin在Maven打包SpringBoot应用时提供了一些额外的支持,如下是它的功能列表:
Goal | Description |
---|---|
spring-boot:repackage | 重新打包为可执行的Jar包或war包 |
spring-boot:run | 本地运行应用程序 |
spring-boot:build-info | 基于当前MavenProject的内容生成build-info.properties信息 |
spring-boot:build-image | 使用buildpack将应用程序打包到OCI映像中 |
spring-boot:start | 启动一个应用程序,一般在集成测试之前执行 |
spring-boot:stop | 停止由start启动的程序,一般在集成测试之后执行 |
spring-boot:help | 在终端显示插件的帮助信息,如mvn spring-boot:help -Ddetail=true -Dgoal=<goal-name> |
重新打包(repackage)功能可以将当前项目代码及所有依赖项打包为一个可执行的Jar包,下面是一个较完整的配置示例:
461<!--可执行Jar包的主启动类-->
2<properties>
3 <start-class>com.szkingdom.kfms.KfmsBootApplication</start-class>
4</properties>
5
6<build>
7 <!--生成的可执行jar包名-->
8 <finalName>my-app</finalName>
9 <plugins>
10 <!--引入SpringBoot Maven Plugin-->
11 <plugin>
12 <groupId>org.springframework.boot</groupId>
13 <artifactId>spring-boot-maven-plugin</artifactId>
14 <executions>
15 <!--执行重新打包-->
16 <execution>
17 <id>repackage</id>
18 <goals>
19 <goal>repackage</goal>
20 </goals>
21 <configuration>
22 <!--默认情况下,repackage生成一个可执行的Jar包,并将原始Jar包以.origin后缀命名-->
23 <!--如果添加classifier属性,则保留原始Jar包,额外生成一个以`-exec.jar`结尾的可执行Jar包-->
24 <classifier>exec</classifier>
25 <!--是否使用可执行Jar包安装到仓库,默认为true(注意:如果未配置classifier,这将导致该Jar包不可依赖)-->
26 <attach>false</attach>
27 </configuration>
28 </execution>
29 </executions>
30 <configuration>
31 <!--可执行Jar包的主启动类-->
32 <mainClass>${start-class}</mainClass>
33 <!--排除一些不打包的依赖-->
34 <excludes>
35 <exclude>
36 <groupId>com.example1</groupId>
37 <artifactId>module1</artifactId>
38 </exclude>
39 </excludes>
40 <!--排除一组不打包的依赖-->
41 <excludeGroupIds>com.example2</excludeGroupIds>
42 </configuration>
43 </plugin>
44 </plugins>
45</build>
46
提示:
更多属性和分层打包请参考官方文档:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#goals-repackage。
分层打包也可以使用
maven-assembly-plugin
插件。
如果SpringBoot Maven Plugin包含build-info目标,则在执行Maven打包时,自动生成META-INF/build-info.properties文件。
221<plugin>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-maven-plugin</artifactId>
4 <executions>
5 <!--生成build-info-->
6 <execution>
7 <goals>
8 <goal>build-info</goal>
9 </goals>
10 </execution>
11 </executions>
12 <configuration>
13 <!--build-info中附加如下4个属性-->
14 <additionalProperties>
15 <encoding.source>UTF-8</encoding.source>
16 <encoding.reporting>UTF-8</encoding.reporting>
17 <java.source>${maven.compiler.source}</java.source>
18 <java.target>${maven.compiler.target}</java.target>
19 </additionalProperties>
20 </configuration>
21</plugin>
22
当项目引入了spring-boot-starter-actuator启动器时,可以访问http://localhost:8080/actuactor/info来查看编译信息。
SpringBoot Maven Plugin的run目标可以在本地启动SpringBoot应用程序,并自定义JVM参数、系统属性、环境变量、程序参数和profile等。
更多资料请查阅官方文档:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#run。
本节请查阅官方文档:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#integration-tests。
如果需要在打包时跳过测试,可使用如下几种方式:
mvn clean install -DskipTests(跳过单元测试)。
mvn clean install -Dmaven.test.skip=true(跳过单元测试及测试代码的编译)。
使用Maven控制台的"闪电"图标。
使用maven-surefire-plugin插件。
131<build>
2 <plugins>
3 <!-- maven 打包时跳过测试 -->
4 <plugin>
5 <groupId>org.apache.maven.plugins</groupId>
6 <artifactId>maven-surefire-plugin</artifactId>
7 <configuration>
8 <skip>true</skip>
9 </configuration>
10 </plugin>
11 </plugins>
12 <build>
13
本节请查阅官方文档:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#build-image。
继承自spring-boot-starter-parent的项目,可以在**/application*.yml(yaml/properties)
中通过@...@
占位符的方式来使用Maven中的扩展属性。
31expanded.project.version=@project.version@
2expanded.project.property=@custom.property@
3
如果没有继承spring-boot-starter-parent,我们需要手动配置这个过滤和扩展。
271<build>
2 <resources>
3 <resource>
4 <directory>${basedir}/src/main/resources</directory>
5 <filtering>true</filtering>
6 <includes>
7 <include>**/application*.yml</include>
8 <include>**/application*.yaml</include>
9 <include>**/application*.properties</include>
10 </includes>
11 </resource>
12 </resources>
13 <plugins>
14 <plugin>
15 <groupId>org.apache.maven.plugins</groupId>
16 <artifactId>maven-resources-plugin</artifactId>
17 <version>2.7</version>
18 <configuration>
19 <delimiters>
20 <delimiter>@</delimiter>
21 </delimiters>
22 <useDefaultDelimiters>false</useDefaultDelimiters>
23 </configuration>
24 </plugin>
25 </plugins>
26</build>
27
如果需要使用${variable.name}
类型的标准占位符,我们需要将useDefaultDelimeters设置为true,并且您的application.properties将如下所示:
31expanded.project.version=${project.version}
2expanded.project.property=${custom.property}
3
更多内容可以查阅SpringBoot官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/index.html。在其附录例举了可可用的属性及说明、自动配置类等。