当一个SpringBoot项目在运行时,开发者需要对SpringBoot项目进行实时监控,获取项目的运行情况,在项目出错时能够实现自动报警等。SpringBoot提供了actuator(读作[ˈæktjuˌeɪtər])来帮助开发者获取应用程序的实时运行数据。开发者可以选择使用HTTP端点或JMX来管理和监控应用程序,获取应用程序的运行数据,包括健康状况、应用信息、内存使用情况等。

端点配置

开启端点

在SpringBoot中开启应用监控非常容易,只需要添加actuator依赖即可,actuator(执行器)是制造业术语,指一个用于移动或控制机械装置的工具,一个很小的变化就能让执行器产生大量的运动。

第一步,创建项目。使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为actuatorspringboot,然后在pom.xml文件中添加如下依赖:

1
2
3
4
5
6
7
8
9
<!--添加actuator依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

开发者可以使用执行器中的端点(EndPoints)对应用进行监控或者与应用进行交互,SpringBoot默认包含许多端点,如下图所示:

如果是一个Web应用,还会有下图的信息:

这些端点大部分都是默认开启的,只有shutdown端点默认未开启,如果需要开启,可以在application.properties配置文件中进行设置:

1
management.endpoint.shutdown.enabled=true

如果开发者不想暴露出这么多端点,那么可以关闭默认的配置,然后手动指定需要开启哪些端点,如下配置表示关闭所有的端点,只开启info端点:

1
2
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true

暴露端点

由于有的端点包含敏感信息,因此端点的启用和暴露需要慎重对待。下图展示了端点的默认暴露情况:

从上图中可以看出,在Web应用中,默认只有health和info两个端点暴露,即当开发者在SpringBoot项目中加入spring-boot-starter-actuator依赖并启动SpringBoot项目后,默认只有这两个端口可以访问,即只能访问以下三个连接:

1
2
3
http://localhost:8080/actuator/health
http://localhost:8080/actuator/info
http://localhost:8080/actuator

其实当你在浏览器中访问http://localhost:8080/actuator的时候,页面返回了一个JSON对象,这个对象中就包含了所有能访问的链接:

开发者可以在application.properties配置文件中自定义需要暴露的端点,举个例子来说,需要暴露mappings和metrics端点,只需要添加如下配置即可:

1
management.endpoints.web.exposure.include=mappings,metrics

如果需要暴露所有的端点,也只需要添加如下配置:

1
management.endpoints.web.exposure.include=*

由于*在YAML格式的配置文件中有特殊的含义,因此如果开发者想在YAML文件中配置暴露所有的端点,可以按照如下方式进行配置:

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: "*"

当配置暴露所有端点后,/actuator接口下的所有子接口都是可以被访问的:

细心的你可能已经发现了,并不是所有的端点都在这个/actuator接口下,这是因为部分端点需要相关依赖才能使用,如sessions站点需要spring-session依赖。对于已经展示出来的接口,开发者可以直接发送相应的请求来查看相关信息,如health端点,如下图所示。status:up表示应用在线,默认展示的health信息较少,后面会详细介绍health端点的其他配置:

端点保护

如果这些端点需要对外提供服务,那么最好能够将这些端点保护起来,若classpath中存在Spring Security,则默认使用Spring Security保护,使用Spring Security保护的步骤非常简单。

首先添加Spring Security依赖,代码如下所示:

1
2
3
4
5
<!--添加security依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后添加Spring Security配置。新建一个config包,并在其中创建ActuatorSecurity类,注意需要继承WebSecurityConfigurerAdapter并重写configure(HttpSecurity http)方法,相应的代码为:

1
2
3
4
5
6
7
8
9
10
@Configuration
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and().httpBasic();
}
}

注意在HttpSecurity中配置所有的Endpoint都需要具有ADMIN角色才能访问,同时开启httpBasic认证。注意EndpointRequest.toAnyEndpoint()表示匹配所有的Endpoint,例如shutdown、mappings、health等,但是不包括开发者通过使用@RequestMapping注解定义的接口(可以参看之前的文章,里面有说明)。

这里为了演示方便就不连接数据库了,而是直接在application.properties配置文件中定义一个用户并进行测试,相应的代码为:

1
2
3
4
# 定义一个security用户信息
spring.security.user.name=envy
spring.security.user.password=1234
spring.security.user.roles=ADMIN

定义完成后,启动SpringBoot项目,再去访问health端口,也就是http://localhost:8080/actuator/health链接时,页面会提示需要登录以后才能进行访问。

端点响应缓存

对于一些不带参数的端点,请求会自动进行缓存,开发者可以通过如下方式配置缓存时间:

1
2
# 配置端点响应缓存
management.endpoint.beans.cache.time-to-live=100ms

这个配置表示beans端点的缓存时间为100ms,如果需要配置其他的端点,只需将beans修改为其他的端点名称即可。注意,如果端点添加了Spring Security保护,那么此时Principal会被视为端点的输入,因此端点响应将不会被缓存。

路径映射

默认情况下,所有端点都暴露在/actuator路径下,例如heal端点的访问路径是/actuator/health,但是开发者需要对端点路径进行定制,可以在application.properties配置文件内添加如下配置:

1
2
3
# 自定义路径映射
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=healthcheck

第一行配置表示将默认的/actuator,修改为/,这行配置会使所有的端点访问路径失去/actuator前缀。第二行的配置表示将/health修改为/healthcheck,修改后health端点的访问路径由之前默认的/actuator/health,变为现在的/healthcheck。此时启动项目,直接在浏览器地址栏中访问http://localhost:8080/可以看到现在的端点信息,这里就不附上图片了。

CORS支持

所有端点默认都没有开启跨域,开发者可以通过在application.properties配置文件内添加如下配置来快速开启CORS支持,进而实现跨域:

1
2
3
# CORS支持
management.endpoints.web.cors.allowed-origins=http://localhost:8081
management.endpoints.web.cors.allowed-methods=GET,POST

上述配置表示允许端点处理来自http://localhost:8081地址的请求,允许的请求方法为GET和POST。

健康信息

(1)展示健康信息详情。
开发者可以通过查看健康信息来获取应用的运行数据,进而提早发现应用问题,提早解决,避免造成损失。默认情况下,开发者只能获取到status信息:

这是因为detail信息默认不显示,开发者可以通过management.endpoint.health.show-details属性来配置detail信息的显示策略,该属性的取值一共有三种:
(1)never,即不显示detail信息,这是默认的设置;(2)when_authorized,details信息只展示给认证用户,即用户登录后可以查看details信息,未登录则不能查看,另外还可以通过management.endpoint.health.roles属性配置要求的角色,如果不配置,那么通过认证的用户都可以查看details信息,如果配置了,如management.endpoint.health.roles=ADMIN则表示认证的用户必须具有ADMIN角色才能查看details信息。(3)always,表示将details信息展示给所有用户。

例如,在pom.xml文件中引入Spring Security后,在application.properties配置文件中增加如下配置:

1
2
3
4
5
6
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=when_authorized
management.endpoint.health.roles=ADMIN
spring.security.user.name=envy
spring.security.user.password=1234
spring.security.user.roles=ADMIN

这里首先暴露所有的端点,配置health的details信息只展示给认证用户,且认证用户还必须具有ADMIN角色,然后配置一个默认的用户,用户名为envy,用户密码为1234,用户角色是ADMIN。

配置完成后,启动SpringBoot项目,并在Postman测试工具中访问health端点,如下图所示:

请注意上面这个链接是需要验证的,因此必须使用Authorization模式。

其实这些信息可以在控制台右侧的Endpoints中进行查看,如下图所示:

健康指示器

SpringBoot会根据classpath中依赖的添加情况来自动配置一些HealthIndicators,如下图所示:

如果项目中存在相关依赖,那么列表中对应的HealthIndicators将会被自动配置。举个例子来说,如果开发人员在pom.xml文件中添加了Redis依赖,且配置好了连接信息,那么此时访问health端点,结果则如下图所示:

若开发者不需要这么多的HealthIndicators,则可以通过如下配置来关闭所有的HealthIndicators自动化配置,只需要在application.properties配置文件内添加如下代码:

1
management.health.defaults.enabled=false

(3)自定义HealthInfo。除了SpringBoot自动收集的这些HealthInfo之外,开发者也可以自定义HealthInfo,只需要实现HealthIndicator接口且重写其中的health方法即可。新建一个component包,并在其中创建一个EnvythinkHealth类,里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
@Component
public class EnvythinkHealth implements HealthIndicator {
@Override
public Health health() {
boolean flag = true;
if(flag){
return Health.up().withDetail("msg","信息正确!").build();
}
return Health.down().withDetail("msg","信息不正确!").build();
}
}

解释一下上述代码的含义:

  • 开发者自定义实现一个EnvythinkHealth类,它实现了HealthIndicator接口,并重写了其中的health方法。在health方法内,定义了一个变量flag,这里设置初始值为true,Health中的up和down方法分别对应两种常见的响应状态:up和down。
  • 默认的响应状态一共有4种,在OrderedHealthAggregator类中(其实准确的说是在Status类中),分别是DOWN、OUT_OF_SERVICE、UP和UNKNOWN。如果开发者想增加响应状态,可以自定义类继承自HealthAggregator类,或者在application.properties配置文件内通过management.health.status.order属性来进行配置。

配置完成后,启动SpringBoot项目,访问http://localhost:8080/actuator/health链接,可以看到访问结果如下图所示:

如果开发者想要增加响应状态FATAL,那么只需在application.properties配置文件内新增如下配置:

1
management.health.status.order=FATAL,DOWN,OUT_OF_SERVICE,UP,UNKNOWN

配置完成后,就可以在health方法中返回自定义的响应状态了,修改EnvythinkHealth的health方法为如下所示:

1
2
3
4
@Override
public Health health() {
return Health.status("FATAL").withDetail("msg","信息错误").build();
}

修改完成后,此时重新启动SpringBoot项目,访问health端点,结果如下图所示:

请注意,此时虽然返回的status为FATAL,但是HTTP的响应码是200,在默认的4种响应状态中,DOWN和OUT_OF_SERVICE的HTTP响应码为503,UP和UNKNOWN的HTTP响应码为200,如果开发者需要对自定义的响应状态配置响应码,只需要在application.properties配置文件中添加如下配置:

1
2
# 响应状态配置响应码
management.health.status.http-mapping.FATAL=503

此时再来访问一下health端点,可以看结果如下:

应用信息

应用信息就是通过/actuator/info接口获取到的信息,主要包含三大类:自定义信息、Git信息以及项目构建信息,接下来就分别进行学习。
(1)自定义信息。
自定义信息可以在application.properties配置文件中添加,也可以在Java代码中添加,个人推荐在配置文件中添加的方式。在application.properties配置文件中添加是指手动定义以info开头的信息,这些信息将在info端点中显示出来。举个例子来说,在application.properties配置文件中添加如下配置信息:

1
2
3
4
5
6
# 自定义信息
info.app.encoding=@project.build.sourceEncoding@
info.app.java.source=@java.version@
info.app.java.target=@java.version@
info.author.name=envyzhan
info.author.email=envyzhan@aliyun.com

请注意,上面的@...@表示引用Maven中的定义。添加完这些配置信息以后,重启SpringBoot项目,访问/autuator/info端点,得到的信息如下所示:

如果你想通过Java代码来实现自定义信息这一目的,只需要自定义类,实现InfoContributor接口并重写其中的contribute(Info.Builder builder)方法即可:

1
2
3
4
5
6
7
8
9
10
@Component
public class EnvythinkInfo implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
Map<String,String> info = new HashMap<>();
info.put("name","envyzhan");
info.put("email","envyzhan@aliyun.com");
builder.withDetail("author",info);
}
}

此时再来访问一下info端点,可以看结果如下:

(2)Git信息。
Git信息是指Git提交信息,当classpath下存在一个git.properties文件时,SpringBoot会自动配置一个GitProperties Bean。开发者可通过Git插件自动生成Git提交信息,然后将这些展示在info端点中。具体的操作步骤如下:

首先进入到当前目录下(这里是指pom.xml文件同级目录),初始化Git仓库并且提交代码到本地仓库,代码如下:

1
2
3
git init
git add .
git commit -m "init project"

注意上面这些操作并没有将项目推送至远程分支,接下来在pom.xml文件中,添加如下plugin:

1
2
3
4
5
<!--添加git-commit插件-->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>

使用该插件来生成Git提交信息,插件添加成功后,接下来在IDEA中单击右侧的Maven Project按钮,然后找到该插件,单击git-commit-id:revision按钮,即可生成Git提交信息,如下图所示:

当出现如下结果,则表明Git信息已经生成完成:

Git提交信息生成成功后,在当前项目的target/classes目录下会看到一个git.properties文件,里面都是Git的提交信息,基本上所有的Git提交信息都包括在内,如分支、提交的版本号、提交的message、提交的用户、用户邮箱等信息:

最后在application.properties配置文件中添加如下配置,表示展示所有的Git提交信息:

1
2
# 展示所有的Git提交信息
management.info.git.mode=full

请注意management.info.git.mode的取值还可以是simple,表示只展示一部分核心提交信息。配置完成后,启动SpringBoot项目,访问info端点,结果如下图所示,所有的Git提交信息都展示出来了:

(3)项目构建信息。
如果classpath下存在META-INF/build-info.properties文件,SpringBoot将自动构建BuildProperties Bean,然后info端点会发布build-info.properties文件中的信息。build-info.properties文件可以通过插件自动生成。具体操作步骤如下:

首先在pom.xml文件中添加如下插件:

1
2
3
4
5
6
7
8
9
10
11
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>

然后在IDEA中单击Maven Project,找到该插件,单击spring-boot:build-info按钮,生成构建信息,如下图所示:

构建信息生成成功后,在当前项目目录下的target/classes/META-INF目录下生成了一个build-info.properties文件,内容如下:

配置完成后,启动SpringBoot项目,访问info端点,结果如下图所示,构建信息都将被自动发布出来了:

监控信息可视化

前面介绍了监控端点,返回JSON数据,但是这样信息查看非常不方便。SpringBoot中提供了监控信息管理端,用来实时监控信息的可视化,这样可以方便开发者快速查看系统的运行状况,而不用一个一个地调用接口。具体的配置步骤如下:

第一步,创建项目。使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为adminspringboot,然后在pom.xml文件中添加如下依赖:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加admin依赖-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.1.0</version>
</dependency>

请注意spring-boot-admin-starter-server的版本极易与SpringBoot的版本产生冲突,这里推荐一个版本为SpringBoot 2.1.14版本,对应spring-boot-admin-starter-server的版本2.1.0,亲测没有Bug出现,其他版本尚未测试。关于的信息,可以点击查看 这里

第二步,启动AdminServer。在项目启动类上添加@EnableAdminServer注解,表示启动AdminServer,相应的代码如下:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableAdminServer
public class AdminspringbootApplication {
public static void main(String[] args) {
SpringApplication.run(AdminspringbootApplication.class, args);
}
}

第三步,启动项目。当上述配置完成以后,启动SpringBoot项目,在浏览器地址栏中输入http://localhost:8080/index.html链接,结果如下所示:

此时Admin端将通过图表的方式展示监控信息。接下来开发Client。Client实际上就是一个一个的服务,Client将被注册到AdminServer然后AdminServer获取Client的运行数据并展示出来。因此这里使用前面的actuatorspringboot项目作为Client。改造时分为以下两个步骤:

第一步,添加相关依赖。在pom.xml文件中添加如下以下:

1
2
3
4
5
6
<!--配置Client依赖-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.1.0</version>
</dependency>

第二步,在application.properties配置文件中新增如下两行配置:

1
2
3
# 配置AdminServer地址
server.port=8081
spring.boot.admin.client.url=http://localhost:8080

请注意此处AdminServer是配置在adminsprigboot项目中的,不是在本actuatorspringboot项目中,但是Client却是在actuatorspringboot项目中。spring.boot.admin.client.url表示配置AdminServer的地址。配置完成后,启动Client项目,此时AdminServer就可以看到Client的运行数据,如下图所示,该图展示了当前注册到AdminServer上Client列表:

如果出现下面的错误:

1
org.springframework.web.reactive.function.BodyExtractors$ReadCancellationException: null

那么说明是actuatorspringboot项目中的SpringSecurity框架引起的冲突,此时需要注释掉pom.xml文件中的SpringSecurity框架依赖,并注释掉其余关于SpringSecurity框架和FATAL的相关信息,然后重新启动就会发现不会再出错误了。

点击AdminServer的Client列表中右上角的Wallboard按钮,它展示了Client的简略信息,如下图所示:

接着单击图中的实例名称,即可看到Client运行的详细数据,如下图所示。一些常见的信息展示在Details选项卡中,其他的选项卡都对应不同的端点数据:

接着点击AdminServer的Client列表中右上角的Journal按钮,它展示了项目运行日志,如下图所示:

邮件报警

虽然使用AdminServer可以实现监控信息可视化,但是项目运维工程师不可能一天24小时都在盯着屏幕查看各个应用的运行状况, 如果在应用运行出问题时能够自动发送邮件通知运维工程师,这样会方便很多。对此,SpringBoot提供了相应的支持,只需要按照如下配置方式进行操作即可。

修改adminsprigboot项目中的Admin工程,在pom.xml文件中新增邮件发送的依赖:

1
2
3
4
5
<!--添加mail发送依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

接着在application.properties配置文件中新增邮件发送的基本信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 邮件发送基本信息
# 设置邮件服务器主机
spring.mail.host=smtp.qq.com
# 设置邮件服务器端口(可以是465或者587)
spring.mail.port=465
# 设置邮件服务器用户名
spring.mail.username=aaaa@qq.com
# 设置邮件服务器密码(注意必须填写授权码)
spring.mail.password=
# 设置邮件默认编码格式
spring.mail.default-encoding=UTF-8
# 设置邮件的SSL连接配置
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
# 开启debug,便于开发者查看邮件发送日志
spring.mail.properties.mail.debug=true


# admin邮件发送功能配置信息
# 邮件的发送者
spring.boot.admin.notify.mail.from=aaaa@qq.com
# 邮件的接收者
spring.boot.admin.notify.mail.to=bbbb@qq.com
# 邮件的抄送人
spring.boot.admin.notify.mail.cc=cccc@qq.com
# 邮件中忽略的信息,也就是忽略掉的事件
spring.boot.admin.notify.mail.ignore-changes=

可以看到关于邮件发送的配置,这里分成了两部分,前者为邮件发送基本信息,后者为admin邮件发送功能配置信息。在admin邮件发送功能配置信息中设置了邮件的发送者、收件人、抄送地址以及忽略的事件。默认情况下,当监控应用应用的状态变为UNKNOWN或者UP时不会发送报警邮件,这里的配置表示被监控应用的任何变化都会发送报警邮件。

配置完成后,重新启动AdminServer,然后启动被监控应用,就会收到应用上线的邮件报警,如下图所示:

现在保持AdminServer所在项目正常运行,停止运行被监控项目也就是actuatorspringboot项目,可以发现此时也会收到应用下线的邮件报警,如下图所示:

应用监控小结

本篇学习了SpringBoot项目中常见的应用监控,分别介绍了端点的配置以及监控数据的可视化, SpringBoot提供的这一整套应用监控解决方案非常强大,在常规项目中稍微修改就可以直接用于生产环境。邮件报警可以使运维工程师及时获取应用的运行信息,特别是在应用程序上下线时及时收到通知后,可以尽早解决问题,进而避免造成一定的损失。