解析springBoot-actuator项目构造中health端点工作原理

目录
  • 前言
  • actuator功能和集成分离
  • actuator自动装载
  • 健康检查指示器配置
  • 健康检查端点配置
  • health健康检查实现
  • 自定义健康检查指示器
  • health其他使用细节
  • 文末结语

前言

最近在一个webflux项目中使用spring-boot-actuator提供的健康检查端点时出了点问题,故对spring-boot-actuator的项目构造,工作原理进行了全面的梳理,标题之所以写明health的工作原理,是因为spring-boot-actuator着实是个大工程,除了提供health端点,还包含了env,log,dump等诸多功能,下面会侧重health健康检查部分,详细探索下。

actuator功能和集成分离

一般在spring boot中使用actuator的时候,会引入下面这个starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在这个starter里面会包含两个依赖,一个是功能实现spring-boot-actuator

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-actuator</artifactId>
      <version>2.1.0.RELEASE</version>
</dependency>

还有一个是和spring boot做集成的config配置,以及Bean自动装配的依赖,如下:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-actuator-autoconfigure</artifactId>
      <version>2.1.0.RELEASE</version>
</dependency>

actuator自动装载

找到spring-boot-actuator-autoconfigure依赖,定位到org.springframework.boot.actuate.autoconfigure.health包下,有如下的结构:

如箭头所指向的HealthEndpointAutoConfiguration.java自动配置类就是actuator中health的启动入口,源码如下:

@Configuration
@EnableConfigurationProperties({ HealthEndpointProperties.class,
      HealthIndicatorProperties.class })
@AutoConfigureAfter(HealthIndicatorAutoConfiguration.class)
@Import({ HealthEndpointConfiguration.class,
      HealthEndpointWebExtensionConfiguration.class })
public class HealthEndpointAutoConfiguration {

}

阅读上面代码需要了解spring boot自动装载机制,这里简单解读下,首先@Configuration开启了配置特性,@EnableConfigurationProperties启用了健康检查端点、健康检查指示器的属性配置,@AutoConfigureAfter定义了健康检查自动装配要在HealthIndicatorAutoConfiguration之后,@Import包含了两个自动装载类,下面详解下三个主要的配置类:

健康检查指示器配置

HEALTHINDICATORAUTOCONFIGURATION

健康检查指示器定义了哪些组件需要被检测,常见的指示器有JDBC数据源(DataSourceHealthIndicator.java),磁盘健康指示器(DiskSpaceHealthIndicator.java)等。每个指示器对应了一个自动装配的类,根据Bean初始化条件去初始化,如JDBC数据源的初始化条件如下:

当上Spring上下文中包含DataSource实施,即开启JDBC健康检查指示器。这些指示器最终会被收集到指示器注册器中DefaultHealthIndicatorRegistry.java

健康检查指示器配置就是完成了指示器注册器的初始化动作,代码如:

@Bean
	@ConditionalOnMissingBean(HealthIndicatorRegistry.class)
	public HealthIndicatorRegistry healthIndicatorRegistry(
			ApplicationContext applicationContext) {
		return HealthIndicatorRegistryBeans.get(applicationContext);
	}
	public static HealthIndicatorRegistry get(ApplicationContext applicationContext) {
		Map<String, HealthIndicator> indicators = new LinkedHashMap<>();
		indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class));
		if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) {
			new ReactiveHealthIndicators().get(applicationContext)
					.forEach(indicators::putIfAbsent);
		}
		HealthIndicatorRegistryFactory factory = new HealthIndicatorRegistryFactory();
		return factory.createHealthIndicatorRegistry(indicators);
	}

可以看到,就是去Spring 应用上下文ApplicationContext中找Bean类型是HealthIndicator.class的实例,如果项目中使用了webFlux,会额外注册Reactive相关的指示器

健康检查端点配置

端点配置比较简单,就是实例化一个HealthEndpoint.java,最终健康检查所有的功能入口都会被抽象汇聚到这个实例里,配置代码如下:

@Configuration
@ConditionalOnSingleCandidate(HealthIndicatorRegistry.class)
class HealthEndpointConfiguration {

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnEnabledEndpoint
	public HealthEndpoint healthEndpoint(HealthAggregator healthAggregator,
			HealthIndicatorRegistry registry) {
		return new HealthEndpoint(
				new CompositeHealthIndicator(healthAggregator, registry));
	}
}

可以看到前提条件是已经有一个健康指示注册器单例实例了

health健康检查实现

在spring-boot-actuator中,定义了@Endpoint注解,用以声明一个actuator端点,health端点也是一样,通过@Endpoint(id="health")暴露了/actuator/health接口。并通过@ReadOperation注解映射了三个方法,如下:

Health health()

访问http://127.0.0.1:8080/actuator/health时会执行这个方法,调用所有的健康指示器实现,并返回结果

Health healthForComponent(@Selector String component)

访问http://127.0.0.1:8080/actuator/health/${component}时会执行这个方法,会根据component的值,找到相关的指示器,并检查返回结果

Health healthForComponentInstance(@Selector String component, @Selector String instance)

访问http://127.0.0.1:8080/actuator/health/${component}/${instance}时会执行这个方法,会根据component、instance的值,找到相关的指示器,并检查返回结果。其中component是组件的name,instance是组件实例的name值。component的name由执行器组件配置类上的注解@ConditionalOnEnabledHealthIndicator来指定,目前包含的指示器组件有如:

我们以redis的指示器RedisHealthIndicator.java来看下,最终指示器是怎么判断组件是否健康的,实现如:

public class RedisHealthIndicator extends AbstractHealthIndicator {
	static final String VERSION = "version";
	static final String REDIS_VERSION = "redis_version";
	private final RedisConnectionFactory redisConnectionFactory;
	public RedisHealthIndicator(RedisConnectionFactory connectionFactory) {
		super("Redis health check failed");
		Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
		this.redisConnectionFactory = connectionFactory;
	}
	@Override
	protected void doHealthCheck(Health.Builder builder) throws Exception {
		RedisConnection connection = RedisConnectionUtils
				.getConnection(this.redisConnectionFactory);
		try {
			if (connection instanceof RedisClusterConnection) {
				ClusterInfo clusterInfo = ((RedisClusterConnection) connection)
						.clusterGetClusterInfo();
				builder.up().withDetail("cluster_size", clusterInfo.getClusterSize())
						.withDetail("slots_up", clusterInfo.getSlotsOk())
						.withDetail("slots_fail", clusterInfo.getSlotsFail());
			}
			else {
				Properties info = connection.info();
				builder.up().withDetail(VERSION, info.getProperty(REDIS_VERSION));
			}
		}
		finally {
			RedisConnectionUtils.releaseConnection(connection,
					this.redisConnectionFactory);
		}
	}
}

可以看到,首先判断了连接的类型时集群模式还是单机模式,然后分别调用了info指令,去拿redis的版本信息

自定义健康检查指示器

了解到这里,自定义实现一个组件的健康检查就容易了。首先自定义指示器继承AbstractHealthIndicator类,实现doHealthCheck方法,然后定义自定义指示器的配置类继承CompositeHealthIndicatorConfiguration就ok了,伪代码如下:

@ConditionalOnEnabledHealthIndicator("myDb")
@Configuration
public class MyHealthIndicatorAutoConfiguration extends CompositeHealthIndicatorConfiguration<DataSourceHealthIndicator,DataSource> {
    @Bean
    @ConditionalOnMissingBean(name = "myDbHealthIndicator")
    public HealthIndicator dbHealthIndicator() {
        return new MyHealthIndicator();
    }
}
class MyHealthIndicator extends AbstractHealthIndicator{
    @Override
    protected void doHealthCheck(Health.Builder builder) {
        //这里定义组建健康的逻辑
        builder.up();
    }
}

health其他使用细节

除了上面提到的健康检查不只/actuator/health端点,还能指定组件检查外,还提供了很多可以通过配置控制的特性,如指示器的开关,什么时候显示健康检查详情等,具体如下:

management.endpoints.web.base-path=/actuator
management.endpoint.health.enabled=true
management.endpoint.health.show-details=never
management.endpoint.health.roles=admin
management.health.db.enabled=true

文末结语

本着用好每一个组件,不放过任何一个实现细节的原则,对spring-boot-actuator中的health实现原理剖析了下。不过actuator真的是个大家伙,光健康检查指示器就有18个实现,特别要说明下的是,针对health,在做健康检查指示器时,会区分web和webFlux。主要原因是在webFlux的环境下,相关的组件也会出Reactive的客户端,比如redis在webFlux下就可以使用Lettuce。

以上就是解析springBoot-actuator中health端点工作原理的详细内容,更多关于springBoot-actuator中health原理的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot服务监控机制原理解析(面试官常问)

    前言 任何一个服务如果没有监控,那就是两眼一抹黑,无法知道当前服务的运行情况,也就无法对可能出现的异常状况进行很好的处理,所以对任意一个服务来说,监控都是必不可少的. 就目前而言,大部分微服务应用都是基于 SpringBoot 来构建,所以了解 SpringBoot 的监控特性是非常有必要的,而 SpringBoot 也提供了一些特性来帮助我们监控应用. 本文基于 SpringBoot 2.3.1.RELEASE 版本演示. SpringBoot 监控 SpringBoot 中的监控可以分为 H

  • Spring Boot Actuator执行器运行原理详解

    Spring Boot执行器(Actuator)提供安全端点,用于监视和管理Spring Boot应用程序. 默认情况下,所有执行器端点都是安全的. 在本章中,将详细了解如何为应用程序启用Spring Boot执行器. 启用Spring Boot Actuator 要为Spring Boot应用程序启用Spring Boot执行器端点,需要在构建配置文件中添加Spring Boot Starter执行器依赖项. Maven用户可以在pom.xml 文件中添加以下依赖项. <dependency>

  • Spring Boot Actuator端点相关原理解析

    Spring Boot Actuator的关键特性是在应用程序里提供众多Web端点,通过它们了解应用程序 运行时的内部状况.有了Actuator,你可以知道Bean在Spring应用程序上下文里是如何组装在一起的,掌握应用程序可以获取的环境属性信息,获取运行时度量信息的快照-- Actuator提供13个端点,可以分为三大类:配置端点.度量端点和其他端点.具体如下表所示: Http方法 路径 描述 get /autoconfig 提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没通过 g

  • Springboot actuator生产就绪功能实现解析

    Spring Boot包含许多附加功能,可帮助您在将应用程序投入生产时对其进行监视和管理.可以选择使用HTTP端点或JMX管理和监视您的应用程序.审核,运行状况和指标收集可以自动应用于您的应用程序. Springboot Actuator,它提供了很多生产级的特性,比如说监控和度量spring boot应用程序.Actuator的这些特性可以通过众多的REST断点,远程shell和JMX获得. 只有基于Spring MVC的应用程序才可以通过HTTP终端来监控应用程序的运行指标. 使用Sprin

  • 详解SpringBoot健康检查的实现原理

    SpringBoot自动装配的套路,直接看 spring.factories 文件,当我们使用的时候只需要引入如下依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 然后在 org.springframework.boot.sprin

  • 解析springBoot-actuator项目构造中health端点工作原理

    目录 前言 actuator功能和集成分离 actuator自动装载 健康检查指示器配置 健康检查端点配置 health健康检查实现 自定义健康检查指示器 health其他使用细节 文末结语 前言 最近在一个webflux项目中使用spring-boot-actuator提供的健康检查端点时出了点问题,故对spring-boot-actuator的项目构造,工作原理进行了全面的梳理,标题之所以写明health的工作原理,是因为spring-boot-actuator着实是个大工程,除了提供hea

  • 解析springboot整合谷歌开源缓存框架Guava Cache原理

    目录 Guava Cache:⾕歌开源缓存框架 Guava Cache使用 使用压测⼯具Jmeter5.x进行接口压力测试: 压测⼯具本地快速安装Jmeter5.x 新增聚合报告:线程组->添加->监听器->聚合报告(Aggregate Report) Guava Cache:⾕歌开源缓存框架 Guava Cache是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效.Guava官网介绍,下面的这几种情况可以考虑使用Guava Cache: 愿意消耗一些内存空间

  • Java中GC的工作原理详细介绍

    Java中GC的工作原理 引子:面试时被问到垃圾回收机制,只是粗略的讲'程序员不能直接对内存操作,jvm负责对已经超过作用域的对象回收处理',面官表情呆滞,也就没再继续深入. 转文: 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能提高整个应用程序的性能.本文将从GC的工作原理.GC的几个关键问题进行探讨,最后提出一些Java程序设计建议,如何从GC角度提高Ja

  • Vue.js中的computed工作原理

    JS属性: JavaScript有一个特性是 Object.defineProperty ,它能做很多事,但我在这篇文章只专注于这个方法中的一个: var person = {}; Object.defineProperty (person, 'age', { get: function () { console.log ("Getting the age"); return 25; } }); console.log ("The age is ", person.

  • JavaScript 中的 this 工作原理

    一.问题的由来 学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果. var obj = { foo: function () {} }; var foo = obj.foo; // 写法一 obj.foo() // 写法二 foo() 上面代码中,虽然obj.foo和foo指向同一个函数,但是执行结果可能不一样.请看下面的例子. var obj = { foo: function () { console.log(this.bar) }, bar: 1 }; v

  • 浅谈Android中AsyncTask的工作原理

    概述 实际上,AsyncTask内部是封装了Thread和Handler.虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池.好了,话不多说了,我们先看看AsyncTask的简单用法吧. AsyncTask使用方法 AsyncTask是一个抽象的泛型类.简单的介绍一下它的使用方式代码如下: package com.example.huangjialin.myapplication;

  • springboot中@Value的工作原理说明

    我们知道springboot中的Bean组件的成员变量(属性)如果加上了@Value注解,可以从有效的配置属性资源中找到配置项进行绑定,那么这一切是怎么发生的呢? 下文将简要分析一下@Value的工作原理. springboot版本: springboot-2.0.6.RELEASE 概述 springboot启动过程中,有两个比较重要的过程,如下: 1 扫描,解析容器中的bean注册到beanFactory上去,就像是信息登记一样. 2 实例化.初始化这些扫描到的bean. @Value的解析

  • Node.js中require的工作原理浅析

    几乎所有的Node.js开发人员可以告诉你`require()`函数做什么,但我们又有多少人真正知道它是如何工作的?我们每天都使用它来加载库和模块,但它的行为,对于我们来说反而是一个谜. 出于好奇,我钻研了node的核心代码来找出在引擎下发生了什么事.但这并不是一个单一的功能,我在node的模块系统的找到了module.js.该文件包含一个令人惊讶的强大的且相对陌生的核心模块,控制每个文件的加载,编译和缓存.`require()`,它的横空出世,只是冰山的一角. module.js 复制代码 代

  • Java中ArrayList的工作原理详解

    1.ArrayList 以数组实现.节约空间,但数组有容量限制.超出限制时会增加50%容量,用System.arraycopy()复制到新的数组.因此最好能给出数组大小的预估值.默认第一次插入元素时创建大小为10的数组.按数组下标访问元素-get(i).set(i,e)的性能很高,这是数组的基本优势.如果按下标插入元素.删除元素-add(i,e).remove(i).remove(e),则要用System.arraycopy()来复制移动部分受影响的元素,性能就变差了.越是前面的元素,修改时要移

  • Java中注解的工作原理

    自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解.这篇文章中,我将向大家讲述到底什么是注解,为什么要引入注解,注解是如何工作的,如何编写自定义的注解(通过例子),什么情况下可以使用注解以及最新注解和ADF(应用开发框架).这会花点儿时间,所以为自己准备一杯咖啡,让我们来进入注解的世界吧. 什么是注解? 用一个词就可以描述注解,那就是元数据,即一种描述数据的数据.所以,可以说

随机推荐