SpringBoot提供了/actuator/health健康检查的接口,接着我们从前往后看这个请求是怎么被SpringBoot处理的,当然入口还是DispatcherServlet。


第一个迭代的是
org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping
它继承了AbstractWebMvcEndpointHandlerMapping,而这个mapping又继承RequestMappingInfoHandlerMapping,接着这个mapping又继承了AbstractHandlerMethodMapping。此时调的这个getHandlerInternal方法就在RequestMappingInfoHandlerMapping中,但是很不幸,它又调了super的也就是AbstractHandlerMethodMapping#getHandlerInternal方法,如下图所示。看起来听绕的,不过都是一层层的继承关系,只不过层次稍微多了点。

看下这个方法:
其中先找到了请求的路径lookupPath即/actuator/health.然后根据这个path在mappingRegistry里找映射的handlerMethod。

这里边很明显的有一个mappingRegistry映射注册表,里边其实就是url和HandlerMapping的映射关系集合。那么,就可以从中找到/actuator/health的HandlerMapping。


也就是org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler#handle(HttpServletRequest, Map)。
然后这个方法就返回了,跳出了org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal之后,又回到了org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler方法,handler非空且非String,那么就看看这个handler有没有定义org.springframework.web.servlet.HandlerInterceptor拦截器?如果定义的话加入到org.springframework.web.servlet.HandlerExecutionChain中。

这个HandlerExecutionChain才是我们要返回的对象,看下它的构造方法,不用多想HandlerMethod和HandlerInterceptor都在其中。

/*** Create a new HandlerExecutionChain.* @param handler the handler object to execute*/public HandlerExecutionChain(Object handler) {this(handler, (HandlerInterceptor[]) null);}

很走运,第一个mapping就找到了我们的结果。

DispatcherServlet拿到了HandlerExecutionChain还不够,还得看内置的Adapter列表中哪一个是支持这个HandlerMethod的。

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

内置的有四个HandlerAdapter,很走运,第一个就合适RequestMappingHandlerAdapter


在执行具体方法前后会执行HandlerInterceptor,但是我们没有定义HandlerInterceptor,这里不考虑,直接跳过。

然后执行org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapterhandle方法。
而RequestMappingHandlerAdapter实现了它。最后执行到RequestMappingHandlerAdapter中的invokeHandlerMethod方法,这个方法哪里通过invocableMethod.invokeAndHandle(webRequest, mavContainer);执行具体调用。一直走下去到org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest方法。如下:

  • getBridgedMethod():就是HandlerMethod的方法。org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler#handle(HttpServletRequest, Map)
  • getBean():就是org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler

来看看在这个

org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler

这个OperationHandler#handle方法中还继续调用了org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.ServletWebOperationAdapter#handle的方法。


可以从headers中看到user-agent是来自于consul的健康检查:

host:“172.30.200.34:8080”,
user-agent:“Consul Health Check”,
accept:“text/plain, text/*, /”,
accept-encoding:“gzip”,
connection:“close”

最后执行的是org.springframework.boot.actuate.endpoint.web.WebOperation接口的实现类org.springframework.boot.actuate.endpoint.web.annotation.DiscoveredWebOperation,这个类继承了org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation。如下:

上图的invoker其实是org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker,看下图就是利用反射机制执行这个invoker的target对象(HealthEndpointWebExtension对象)的health方法。



沿着逻辑一直往下走,会走到org.springframework.boot.actuate.health.HealthIndicatorgetHealth方法。
但这个方法是个抽象方法,需要子类去覆盖。在子类中我么可以去做一些操作,比如判断服务如果没有注册到consul,则将服务重新注册到consul上。因为实际生产中可能会出现consul集群宕机后重启的情况,此时就需要在感知到/actuator/health健康检查到来的时候重新注册上去。

如果重新注册成功,我们就可以将服务标识为健康:

Health health = new Health.Builder().up().build();

并返回。

在SpringBoot中有一个实现,默认情况下Conusl会定时(10s)发送请求/actuator/health到这个类中,直接返回的up。当然我们也可以自定义。


/** Copyright 2012-2019 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.boot.actuate.health;/*** Default implementation of {@link HealthIndicator} that returns {@link Status#UP}.** @author Dave Syer* @author Christian Dupuis* @since 2.2.0* @see Status#UP*/
public class PingHealthIndicator extends AbstractHealthIndicator {@Overrideprotected void doHealthCheck(Health.Builder builder) throws Exception {builder.up();}}

源码分析:SpringBoot健康检查相关推荐

  1. 深入源码分析SpringBoot中使用@ConditionalOnBean无效的问题(@ConditionalOnBean did not find any beans of type)

    一.前言 最近在使用SpringBoot的@ConditionalOnBean的时候遇到一个很很奇特的问题.即在@Bean中使用@ConditionalOnBean注解,在可以确保需要依赖的Bean一 ...

  2. springboot自动配置文件读取以及源码分析

    今天来讲讲springboot自动配置文件读取以及源码分析 springboot启动之后 1.首先进入@springbootApplication(如上图) 里面的**@EnableAutoConfi ...

  3. springboot源码分析

    快速开发底层原理 SpringBoot核心理念 能够实现帮助开发者快速的整合第三方框架(Spring.Mybatis.hibernate) 原理:Maven依赖封装整合和自定义starter. 完全去 ...

  4. Nacos 服务端健康检查及客户端服务订阅机制源码分析(三)

    Nacos 服务端健康检查 长连接 概念:长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发送链路检测包 注册中心客户端 2.0 以后使用 gRPC 代替 h ...

  5. springboot启动源码分析3-环境配置

    applyInitializersSpringBoot启动源码分析3--环境配置 springboot启动源码分析1--初步初始化 springboot启动源码分析2--run方法分析 springb ...

  6. SpringBoot自定义异常源码分析

    SpringBoot自定义异常源码分析 在类上加ControllerAdvice注解,在方法上加ExceptionHandler注解,就可以在方法里处理相应的异常. 1.自定义异常处理类Additio ...

  7. springboot 事务_原创002 | 搭上SpringBoot事务源码分析专车

    前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往Spring Boot事务源码分析的专车 专车问题 为什么 ...

  8. 【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )

    文章目录 一.回调 StateChangedListener 接口 二.JobHandler 处理 ( 任务检查 ) 三.maybeRunPendingJobsH 方法 四.assignJobsToC ...

  9. springboot集成mybatis源码分析-mybatis的mapper执行查询时的流程(三)

    springboot集成mybatis源码分析-mybatis的mapper执行查询时的流程(三) 例: package com.example.demo.service;import com.exa ...

  10. springboot集成mybatis源码分析-启动加载mybatis过程(二)

    springboot集成mybatis源码分析-启动加载mybatis过程(二) 1.springboot项目最核心的就是自动加载配置,该功能则依赖的是一个注解@SpringBootApplicati ...

最新文章

  1. python界面开发-python 图形界面编程(GUI)
  2. 如何用Python画一个中国地图?
  3. [蓝桥杯2017初赛]方格分割-dfs+思维
  4. linux c计算两个int相除求百分比的实现
  5. 15.01.29-MVC中用Areas分解项目
  6. 这个黑科技耳机方便又时尚,听歌也不怕坐过
  7. 一个定时器的普通实现,多进程实现和多线程实现的对比
  8. Android动画分类与总结
  9. 256QAM调制映射表
  10. 【手撕算法】PatchMatch图像修复算法C++实现
  11. java烟花代码详细步骤,一文说清!
  12. 华为 服务器 驱动 linux,华为服务器SAS控制器驱动问题
  13. 完成静态服务器——Node.js摸石头系列之四
  14. GB/T18655-2010标准下的动力电池系统及其BMS电磁EMC测试
  15. Adobe Flash Player已不再受支持怎么解决?
  16. 2018年上半年系统分析师上午试题答案
  17. matlab装在哪个盘,安装换盘问题
  18. hive窗口函数练习题
  19. ps样式如何导入?Photoshop样式导入教程
  20. 编写一个方法去掉数组里面重复的内容 var arr=['abc','abcd','sss','2','d','t','2','ss','f','22','d'];...

热门文章

  1. Linux01---Linux常用命令
  2. matlab绘制磁场图,基于Matlab的电磁场图示化教学
  3. java8 .map是什么意思_JDK8 stream().map() 作用
  4. java对象上有横线_对象bean间属性值复制:无视大小写和下划线_和横杠-
  5. qq话题怎么引流?QQ空间说说引流技巧,QQ引流有什么好方法?
  6. 父母教养方式与幼儿焦虑关系的三水平元分析
  7. 萌新做点小玩意儿DAY-15 线性表(顺序表)及其应用
  8. Android开发环境配置简介
  9. 计算机科学技术考研内容,计算机科学与技术考研考哪些科目?
  10. Nginx服务器启停命令