在之前的系列文章中我们学习了如何进行Spring Boot应用的功能开发,以及如何写单元测试、集成测试等,然而,在实际的软件开发中需要做的不仅如此:还包括对应用程序的监控和管理。
正如飞行员不喜欢盲目飞行,程序员也需要实时看到自己的应用目前的运行情况。如果给定一个具体的时间,我们希望知道此时CPU的利用率、内存的利用率、数据库连接是否正常以及在给定时间段内有多少客户请求等指标;不仅如此,我们希望通过图表、控制面板来展示上述信息。最重要的是:老板和业务人员希望看到的是图表,这些比较直观易懂。
首先,这篇文章讲介绍如何定制自己的health indicator。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
info.build.artifact=@project.artifactId@ info.build.name=@project.name@ info.build.description=@project.description@ info.build.version=@project.version@
<resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources>
然后在
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <delimiters> <delimiter>@</delimiter> </delimiters> <useDefaultDelimiters>false</useDefaultDelimiters> </configuration> </plugin>
public class DbCountHealthIndicator implements HealthIndicator { private CrudRepository crudRepository; public DbCountHealthIndicator(CrudRepository crudRepository) { this.crudRepository = crudRepository; } @Override public Health health() { try { long count = crudRepository.count(); if (count >= 0) { return Health.up().withDetail("count", count).build(); } else { return Health.unknown().withDetail("count", count).build(); } } catch (Exception e) { return Health.down(e).build(); } } }
@Autowired private HealthAggregator healthAggregator; @Bean public HealthIndicator dbCountHealthIndicator(Collection<CrudRepository> repositories) { CompositeHealthIndicator compositeHealthIndicator = new CompositeHealthIndicator(healthAggregator); for (CrudRepository repository: repositories) { String name = DbCountRunner.getRepositoryName(repository.getClass()); compositeHealthIndicator.addHealthIndicator(name, new DbCountHealthIndicator(repository)); } return compositeHealthIndicator; }
Spring Boot Autuator这个库包括很多自动配置,对外开放了很多endpoints,通过这些endpoints可以访问应用的运行时状态:
上述各个endpoint是Spring Boot Actuator提供的接口和方法,接下来看看我们自己定制的 HealthIndicator ,我们只需要实现 HealthIndicator 接口,Spring Boot会收集该接口的实现,并加入到 /health 这个endpoint中。
在我们的例子中,我们为每个 CrudRepository 实例都创建了一个 HealthIndicator 实例,为此我们创建了一个 CompositeHealthIndicator 实例,由这个实例管理所有的 DbHealthIndicator 实例。作为一个 composite ,它会提供一个内部的层次关系,从而可以返回JSON格式的数据。
代码中的 HealthAggregator 实例的作用是:它维护一个map,告诉 CompositeHealthIndicator 如何决定所有 HealthIndicator 代表的整体的状态。例如,除了一个repository返回DOWN其他的都返回UP,这时候这个composite indicator作为一个整体应该返回UP还是DOWN, HealthAggregator 实例的作用就在这里。
Spring Boot使用的默认的 HealthAggregator 实现是 OrderedHealthAggregator ,它的策略是手机所有的内部状态,然后选出在DOWN、OUT_OF_SERVICE、UP和UNKNOWN中间具有最低优先级的那个状态。这里使用策略设计模式,因此具体的状态判定策略可以改变和定制,例如我们可以创建定制的 HealthAggregator :
最后需要考虑下安全问题,通过这些endpoints暴露出很多应用的信息,当然,Spring Boot也提供了配置项,可以关闭指定的endpoint——在application.properties中配置
还可以通过设置 management.port=-1 关闭endpoint的HTTP访问接口,或者是设置其他的端口,供内部的admin服务访问;除了控制端口,还可以设置仅仅让本地访问,只需要设置 management.address=127.0.0.1 ;通过设置 management.context-path=/admin ,可以设置指定的根路径。综合下,经过上述设置,在本地访问 http://127.0.0.1/admin/health 来访问健康状态。
可以在防火墙上屏蔽掉不是/admin/*的endpoints访问请求,更进一步,利用Spring Security可以配置验证信息,这样要访问当前应用的endpoints必须使用用户名和密码登陆。
本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。