Spring Boot微服务项目实战(第2版)学习笔记-第15章Spring Boot应用监控
Spring Boot应用监控
本章主要介绍如何通过Spring Boot监控和管理应用、自定义监控端点以及自定义HealthIndicator等内容。
1.应用监控介绍
Spring Boot大部分模块都是用于开发业务功能或者连接外部资源。除此之外,Spring Boot还提供了spring-boot-starter-actuator模块,该模块主要用于管理和监控应用,它是一个用于暴露自身信息的模块,可以有效地减少监控系统在采集应用指标时的开发量。
spring-boot-starter-actuator模块提供了监控和管理端点以及一些常用的扩展和配置方式,具体如表所示。
2.使用监控
2.1 引入依赖
在Spring Boot中使用监控,首先需要在pom.xml文件中引入所需的依赖spring-boot-starter-actuator,具体代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
2.2 添加配置
在pom.xml文件引入spring-boot-starter-actuator依赖包之后,需要在application.properties文件中添加如下的配置信息:
### 应用监控配置
# 指定访问这些监控方法的端口
management.server.port=8080
- management.server.port:用于指定访问这些监控方法的端口。
2.3 测试
spring-boot-starter-actuator依赖和配置都添加成功之后,重新启动spring-boot-book-v2项目,项目启动成功之后,在浏览器中输入http://localhost:8080/actuator,可以看到如图所示的输出信息。
从图中可以看出,actuator只暴露了3个简单的endpoint,并且只有/health接口的内容还有点用,可以检查应用服务是否健康。当然,actuator绝对不止这么点功能,只是出于安全考虑,其余的endpoint默认被禁用了。在浏览器中输入:http://localhost:8080/actuator/health,可以看到应用的健康信息,“UP”代表应用是健康状态。
为了简单起见,我们来开启所有的接口。只需要在application.properties文件中加入一行配置即可:
### 开启所有的端点
management.endpoints.web.exposure.include=*
重新在浏览器中输入http://localhost:8080/actuator,便可以看到所有的endpoint,如图所示。
对于不带任何参数的读取操作,端点自动缓存对其响应。要配置端点缓存响应的时间,请使用cache.time-live属性,以下示例将beans端点缓存的生存时间设置为10秒:
默认情况下,端点通过使用端点的ID在/actuator路径下的HTTP上公开,例如,beans端点暴露在/actuator/beans下。如果要将端点映射到其他路径,则可以使用management.endpoints.web.path-mapping属性。另外,如果想更改基本路径,则可以使用management.endpoints.web.base-path。以下示例将/actuator/health重新映射到/healthcheck:
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=healthcheck
要配置单个端点的启用,请使用management.endpoint.<id>.enabled属性,以下示例启用了shutdown端点:
management.endpoint.shutdown.enabled= true
另外,可以通过management.endpoints.enabled-by-default来修改全局端口的默认配置,以下示例启用info端点并禁用所有其他端点:
management.endpoints.enabled-by-default=false
management.endpoints.info.enabled=true
其他端点测试,可以按照表所示的访问路径依次访问测试。
在浏览器中可以把返回的数据格式化成json格式,这是因为在Google浏览器中安装了JsonView插件,具体安装步骤如下:
- 浏览器中输入链接:https://github.com/search?utf8=%E2%9C%93&q=jsonview,在弹出的页面中单击gildas-lormeau/JSONView-for-Chrome,如图所示。
- 单击【Download Zip】,插件下载完成,解压缩到相应目录中(D:\Download\JSONView-for-Chrome-master)。
- 在浏览器右上角单击【更多工具】→【扩展程序】→【加载已解压的扩展程序】。选择插件目录(D:\Download\JSONView-for-Chrome-master\WebContent)。
- 安装完成后,重新启动浏览器(快捷键Ctrl+R)。
3.自定义端点
3.1 自定义端点EndPoint
spring-boot-starter-actuator模块中已经提供了许多原生端点。根据端点的作用,我们可以把原生端点分为以下3大类。
- 应用配置类:获取应用程序中加载的应用配置、环境变量、自动化配置报告等与Spring Boot应用密切相关的配置类信息。
- 度量指标类:获取应用程序运行过程中用于监控的度量指标,比如内存信息、线程池信息、HTTP请求统计等。
- 操作控制类:提供了对应用的关闭等操作类功能。
如果spring-boot-starter-actuator模块提供的这些原生端点无法满足需求,还可以自定义端点,自定义端点时,只要继承抽象类AbstractEndpoint即可。这里在spring-boot-book-v2目录/src/main/java/com.example.demo下新建actuator包,在actuator包下新建自定义端点类AyUserEndPoint,AyUserEndPoint主要用来监控数据库用户信息情况,比如用户总数量、被删除用户数量、活跃用户数量等。自定义端点AyUserEndPoint类的代码如下:
@Component
@Endpointid="userEndPoints")
public class AyUserEndpoint {
@Resource
private AyUserService ayUserService;
@ReadOperation
public Map<String, Object> invoke(){
Map<String,Object> map = new HashMap<String, Object>();
//当前时间
map.put("current_time",new Date());
//用户总数量
map.put("user_num", ayUserService.findUserTotalNum());
return map;
}
}
- @Endpoint(id=“userEndPoints”):@Endpoint注解简化了创建用户自定义端点的过程,@Endpoint相当于@WebEndpoint和@JmxEndpoint的整合,Web和jmx方式都支持。
- @WebEndpoint:只会生成Web的方式的端点监控。
- @JmxEndpoint:只会生成Jmx的方式监控。
在AyUserEndPoint类中,我们注入AyUserService接口,并在invoke方法中调用findUserTotalNum方法,查询当前数据库总的用户数。所以需要在AyUserService接口中添加方法findUserTotalNum,具体代码如下:
//查询用户数量
Long findUserTotalNum();
同时,在AyUserServiceImpl类中实现方法findUserTotalNum,具体代码如下:
@Override
public Long findUserTotalNum(){
return ayUserRepository.count();
}
AyUserService类与AyUserServiceImpl类开发完成之后,就可以在invoke方法中使用。在invoke方法中定义Map集合,并向Map集合存放当前时间current_time和数据库用户总数user_num。
3.2 测试
代码开发完成之后,重启启动spring-boot-book-v2项目,在浏览器中输入访问地址:http://localhost:8080/actuator/userEndPoints,便可以看到请求到数据,具体数据如下:
{"user_num" : 3, "current":1512817762910}
从返回数据中,可以看出当前数据库总共有3个用户,以及当前具体时间(毫秒)。
3.3 自定义HealthIndicator
默认端点Health的信息是从HealthIndicator的bean中收集的,Spring中内置了一些HealthIndicator,如表所示。
启动项目spring-boot-book-v2,在浏览器中输入访问链接:http://localhost:8080/actuator/health,可以看到返回的Spring Boot应用健康数据只有:
{
"status":"UP"
}
如果想要查看详细的应用健康信息,需要添加以下配置:
management.endpoint.health.show-details=always
配置完成之后,再次访问http://localhost:8080/actuator/health,获取的信息如下:
从上面的信息中,可以方便地查看目前应用所依赖资源(Redis、MongoDB)的运行情况及其他信息。
Tips:management.endpoint.health.show-details的值除了always之外还有when-authorized、never,默认值是never。
如果想要自定义符合自己业务需求的检查健康,需要自定义HealthIndicator来获得更多应用健康的信息。在spring-boot-book-v2项目目录/src/main/java/com.example.actuator下新建MyHealthIndicator类,该类实现HealthIndicator接口并重写health方法,MyHealthIndicator类具体代码如下:
@Component
public class MyHealthIndicator implements HealthIndicator{
@Override
public Health health(){
Long totalSpace = checkTocalSpace();
Long free checkFree();
String status= checkstatus();
checkFree();
return new Health.Builder()
.up()
.withDetail("status", status)
.withDetail("total", totalSpace)
.withDetail("free", free)
.build();
}
private String checkStatus(){
//结合真实项目,获取相关参数
return "Up";
}
private Long checkTocalSpace(){
//结合真实项目,获取相关参数
return 10000L;
}
private Long checkFree (){
//结合真实项目,获取相关参数
return 5000L;
}
}
3.4 测试
代码开发完成之后,重新启动spring-boot-book-v2项目,项目启动成功之后,在浏览器中输入访问链接:http://localhost:8080/actuator/health,可以获得自定义健康类MyHealthIndicator返回的结果,具体结果信息如下:
my: {
status:"UP",
total: 10000,
free: 5000
}
//忽略其他健康数据
从上面返回的json结果信息可以看出,json结果信息的key:my,也就是英文MyHealthIndicator去掉HealthIndicator。如果自定义健康类取名为MyDefineHealthIndicator,则返回结果信息将会变成:
myDefine: {
status:"UP",
total: 10000,
free: 5000
}
//忽略其他健康数据
一般情况下,不会直接实现 HealthIndicator接口,而是继承AbstractHealthIndicator抽象类。因此,我们只需要重写doHealthCheck方法,并在这个方法中关注具体的健康检测的业务逻辑服务即可。
4.保护Actuator端点
Actuator端点发布的信息很多都涉及敏感信息和高危操作。比如/shutdown端点,它可以直接关闭应用程序,如果随便某个人都有权限访问该端点,那是非常危险的。因此,有必要控制Actuator端点的访问权限以避免Actuator端点被非法访问。想要保护Actuator端点,可以使用保护其他URL路径一样的方式,通过使用Spring Security来控制URL路径的授权访问。
在第14章中,我们已经在Spring Boot中集成了Spring Security,并且开发了WebSecurityConfig配置类对用户登录进行授权访问,现在我们改造该类,具体代码如下:
@Configuration
@EnableWebSecurity
public class WebsecurityConfig extends WebSecurityConfigurerAdapter {
//省略代码
@Override
protected void configure(HttpSecurity http) throws Exception {
//路由策略和访问权限的简单配置
http
.authorizeRequests()
//要求有管理员的权限
//登录失败返回URL:/loginerror.antMatchers("/shutdown").access("hasRole('ADMIN')")
//登录成功跳转URL,这里跳转到用户首页
//登录页面全部权限可访问
.antMatchers("/**").permitAll()
.and()
.formLogin()
//启用默认登录页面
.failureUrl("/login?error")
.defaultSuccessUrl("/ayUser/test")
.permitAll();
super.configure(http);
}
}
通过使用antMatchers("/shutdown").access(“hasRole(‘READER’)”)方法,对/shutdown进行授权访问,/shutdown端点现在仅允许拥有ADMIN权限的用户进行访问。
端点/shutdown已经被保护起来了,假如现在想保护其他端点,例如/metrics、/health等,只需要为antMatchers()传入输入参数即可。具体代码如下:
.authorizeRequests()
//要求有管理员的权限
.antMatchers("/shutdown","/metrics","/health").access("hasRole('READER')")
如果觉得每次添加一个端点的访问权限都得在antMatchers()方法中修改很麻烦,可以在application.properties配置文件中配置端点访问的上下文,具体配置如下:
### 配置端点访问的上下文路径
management.endpoints.web.base-path=/manage
此时,在为Actuator端点赋予ADMIN权限限制的时候就能借助这个上下文/manage:
//要求有管理员的权限
.antMatchers("/manage/**").access("hasRole('READER')")