解析springBoot-actuator項(xiàng)目構(gòu)造中health端點(diǎn)工作原理
前言
最近在一個(gè)webflux項(xiàng)目中使用spring-boot-actuator提供的健康檢查端點(diǎn)時(shí)出了點(diǎn)問題,故對spring-boot-actuator的項(xiàng)目構(gòu)造,工作原理進(jìn)行了全面的梳理,標(biāo)題之所以寫明health的工作原理,是因?yàn)閟pring-boot-actuator著實(shí)是個(gè)大工程,除了提供health端點(diǎn),還包含了env,log,dump等諸多功能,下面會側(cè)重health健康檢查部分,詳細(xì)探索下。
actuator功能和集成分離
一般在spring boot中使用actuator的時(shí)候,會引入下面這個(gè)starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
在這個(gè)starter里面會包含兩個(gè)依賴,一個(gè)是功能實(shí)現(xiàn)spring-boot-actuator
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> <version>2.1.0.RELEASE</version> </dependency>
還有一個(gè)是和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包下,有如下的結(jié)構(gòu):
如箭頭所指向的HealthEndpointAutoConfiguration.java自動配置類就是actuator中health的啟動入口,源碼如下:
@Configuration @EnableConfigurationProperties({ HealthEndpointProperties.class, HealthIndicatorProperties.class }) @AutoConfigureAfter(HealthIndicatorAutoConfiguration.class) @Import({ HealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class }) public class HealthEndpointAutoConfiguration { }
閱讀上面代碼需要了解spring boot自動裝載機(jī)制,這里簡單解讀下,首先@Configuration開啟了配置特性,@EnableConfigurationProperties啟用了健康檢查端點(diǎn)、健康檢查指示器的屬性配置,@AutoConfigureAfter定義了健康檢查自動裝配要在HealthIndicatorAutoConfiguration之后,@Import包含了兩個(gè)自動裝載類,下面詳解下三個(gè)主要的配置類:
健康檢查指示器配置
HEALTHINDICATORAUTOCONFIGURATION
健康檢查指示器定義了哪些組件需要被檢測,常見的指示器有JDBC數(shù)據(jù)源(DataSourceHealthIndicator.java),磁盤健康指示器(DiskSpaceHealthIndicator.java)等。每個(gè)指示器對應(yīng)了一個(gè)自動裝配的類,根據(jù)Bean初始化條件去初始化,如JDBC數(shù)據(jù)源的初始化條件如下:
當(dāng)上Spring上下文中包含DataSource實(shí)施,即開啟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 應(yīng)用上下文ApplicationContext中找Bean類型是HealthIndicator.class的實(shí)例,如果項(xiàng)目中使用了webFlux,會額外注冊Reactive相關(guān)的指示器
健康檢查端點(diǎn)配置
端點(diǎn)配置比較簡單,就是實(shí)例化一個(gè)HealthEndpoint.java,最終健康檢查所有的功能入口都會被抽象匯聚到這個(gè)實(shí)例里,配置代碼如下:
@Configuration @ConditionalOnSingleCandidate(HealthIndicatorRegistry.class) class HealthEndpointConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint public HealthEndpoint healthEndpoint(HealthAggregator healthAggregator, HealthIndicatorRegistry registry) { return new HealthEndpoint( new CompositeHealthIndicator(healthAggregator, registry)); } }
可以看到前提條件是已經(jīng)有一個(gè)健康指示注冊器單例實(shí)例了
health健康檢查實(shí)現(xiàn)
在spring-boot-actuator中,定義了@Endpoint注解,用以聲明一個(gè)actuator端點(diǎn),health端點(diǎn)也是一樣,通過@Endpoint(id="health")暴露了/actuator/health接口。并通過@ReadOperation注解映射了三個(gè)方法,如下:
Health health()
訪問http://127.0.0.1:8080/actuator/health時(shí)會執(zhí)行這個(gè)方法,調(diào)用所有的健康指示器實(shí)現(xiàn),并返回結(jié)果
Health healthForComponent(@Selector String component)
訪問http://127.0.0.1:8080/actuator/health/${component}時(shí)會執(zhí)行這個(gè)方法,會根據(jù)component的值,找到相關(guān)的指示器,并檢查返回結(jié)果
Health healthForComponentInstance(@Selector String component, @Selector String instance)
訪問http://127.0.0.1:8080/actuator/health/${component}/${instance}時(shí)會執(zhí)行這個(gè)方法,會根據(jù)component、instance的值,找到相關(guān)的指示器,并檢查返回結(jié)果。其中component是組件的name,instance是組件實(shí)例的name值。component的name由執(zhí)行器組件配置類上的注解@ConditionalOnEnabledHealthIndicator來指定,目前包含的指示器組件有如:
我們以redis的指示器RedisHealthIndicator.java來看下,最終指示器是怎么判斷組件是否健康的,實(shí)現(xiàn)如:
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); } } }
可以看到,首先判斷了連接的類型時(shí)集群模式還是單機(jī)模式,然后分別調(diào)用了info指令,去拿redis的版本信息
自定義健康檢查指示器
了解到這里,自定義實(shí)現(xiàn)一個(gè)組件的健康檢查就容易了。首先自定義指示器繼承AbstractHealthIndicator類,實(shí)現(xiàn)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其他使用細(xì)節(jié)
除了上面提到的健康檢查不只/actuator/health端點(diǎn),還能指定組件檢查外,還提供了很多可以通過配置控制的特性,如指示器的開關(guān),什么時(shí)候顯示健康檢查詳情等,具體如下:
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
文末結(jié)語
本著用好每一個(gè)組件,不放過任何一個(gè)實(shí)現(xiàn)細(xì)節(jié)的原則,對spring-boot-actuator中的health實(shí)現(xiàn)原理剖析了下。不過actuator真的是個(gè)大家伙,光健康檢查指示器就有18個(gè)實(shí)現(xiàn),特別要說明下的是,針對health,在做健康檢查指示器時(shí),會區(qū)分web和webFlux。主要原因是在webFlux的環(huán)境下,相關(guān)的組件也會出Reactive的客戶端,比如redis在webFlux下就可以使用Lettuce。
以上就是解析springBoot-actuator中health端點(diǎn)工作原理的詳細(xì)內(nèi)容,更多關(guān)于springBoot-actuator中health原理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于JavaMail實(shí)現(xiàn)郵件發(fā)送
這篇文章主要為大家詳細(xì)介紹了基于JavaMail實(shí)現(xiàn)郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Java-Redis-Redisson分布式鎖的功能使用及實(shí)現(xiàn)
這篇文章主要介紹了Java-Redis-Redisson-分布式鎖的功能使用及實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08淺談Spring AOP中args()和argNames的含義
這篇文章主要介紹了Spring AOP中args()和argNames的含義,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Java數(shù)組常用排序算法實(shí)例小結(jié)
這篇文章主要介紹了Java數(shù)組常用排序算法,結(jié)合實(shí)例形式總結(jié)分析了java數(shù)組常用的4種排序算法,包括冒泡排序、數(shù)組遞增排序、快速排序及選擇排序,需要的朋友可以參考下2017-12-12