惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Troy Hunt's Blog
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
F
Full Disclosure
Recorded Future
Recorded Future
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
博客园_首页
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Hacker News: Front Page
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
博客园 - 司徒正美
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
Help Net Security
Help Net Security
Cloudbric
Cloudbric
PCI Perspectives
PCI Perspectives
有赞技术团队
有赞技术团队
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
TaoSecurity Blog
TaoSecurity Blog
L
Lohrmann on Cybersecurity
量子位
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tailwind CSS Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
P
Proofpoint News Feed
N
News and Events Feed by Topic
罗磊的独立博客
T
Threat Research - Cisco Blogs
Schneier on Security
Schneier on Security
T
Tor Project blog
IT之家
IT之家
M
MIT News - Artificial intelligence
S
Security @ Cisco Blogs
O
OpenAI News
AI
AI
S
Securelist
Simon Willison's Weblog
Simon Willison's Weblog
The Last Watchdog
The Last Watchdog
月光博客
月光博客
Security Archives - TechRepublic
Security Archives - TechRepublic
L
LINUX DO - 热门话题

博客园 - 意犹未尽

从提示词工程到 Harness 设计范式 VsCode AI生态开源项目 掌握Redis集群通信,解决数据存取难题 jvm堆外内存-direct buffer 服务治理 概念、架构、协议格式到裸协议实现,彻底搞懂 MCP 的本质 maven-antrun-plugin插件 Spring AI-MCP源码整理 java响应式编程基础 压测实践案例之网关 elasticseach-分页搜索 sentinel增加ip来源限流后占用服务高内存问题分析 spring-boot-actuator elasticseach-head插件安装及使用 设计模式之美学习-代码命名规范 ES-Client-api-easy es sentinel-ProcessorSlot sentinel-SPI初始化时机 记录一次内存泄漏排查 设计思路之系统做深能力的思维方式
spring-boot-actuator-Health原理
意犹未尽 · 2025-11-04 · via 博客园 - 意犹未尽

说明

在容器化部署下,如何判断服务是否健康通过 curl  127.0.0.1:8080/actuator/health检查 是否是健康状态

使用示例以sentinel为例

实现抽象类

public class SentinelHealthIndicator extends AbstractHealthIndicator {

    private DefaultListableBeanFactory beanFactory;

    private SentinelProperties sentinelProperties;

    public SentinelHealthIndicator(DefaultListableBeanFactory beanFactory,
            SentinelProperties sentinelProperties) {
        this.beanFactory = beanFactory;
        this.sentinelProperties = sentinelProperties;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        Map<String, Object> detailMap = new HashMap<>();

        // If sentinel isn't enabled, set the status up and set the enabled to false in
        // detail
        if (!sentinelProperties.isEnabled()) {
            detailMap.put("enabled", false);
            builder.up().withDetails(detailMap);
            return;
        }

        detailMap.put("enabled", true);

        // Check health of Dashboard
        boolean dashboardUp = true;
        List<Tuple2<String, Integer>> consoleServerList = TransportConfig
                .getConsoleServerList();
        if (CollectionUtils.isEmpty(consoleServerList)) {
            // If Dashboard isn't configured, it's OK and mark the status of Dashboard
            // with UNKNOWN.
            detailMap.put("dashboard",
                    new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
        }
        else {
            // If Dashboard is configured, send a heartbeat message to it and check the
            // result
            HeartbeatSender heartbeatSender = HeartbeatSenderProvider
                    .getHeartbeatSender();
            boolean result = heartbeatSender.sendHeartbeat();
            if (result) {
                detailMap.put("dashboard", Status.UP);
            }
            else {
                // If failed to send heartbeat message, means that the Dashboard is DOWN
                dashboardUp = false;
                detailMap.put("dashboard",
                        new Status(Status.UNKNOWN.getCode(), String.format(
                                "the dashboard servers [%s] one of them can't be connected",
                                consoleServerList)));
            }
        }

        // Check health of DataSource
        boolean dataSourceUp = true;
        Map<String, Object> dataSourceDetailMap = new HashMap<>();
        detailMap.put("dataSource", dataSourceDetailMap);

        // Get all DataSources and each call loadConfig to check if it's OK
        // If no Exception thrown, it's OK
        // Note:
        // Even if the dynamic config center is down, the loadConfig() might return
        // successfully
        // e.g. for Nacos client, it might retrieve from the local cache)
        // But in most circumstances it's okay
        Map<String, AbstractDataSource> dataSourceMap = beanFactory
                .getBeansOfType(AbstractDataSource.class);
        for (Map.Entry<String, AbstractDataSource> dataSourceMapEntry : dataSourceMap
                .entrySet()) {
            String dataSourceBeanName = dataSourceMapEntry.getKey();
            AbstractDataSource dataSource = dataSourceMapEntry.getValue();
            try {
                dataSource.loadConfig();
                dataSourceDetailMap.put(dataSourceBeanName, Status.UP);
            }
            catch (Exception e) {
                // If one DataSource failed to loadConfig, means that the DataSource is
                // DOWN
                dataSourceUp = false;
                dataSourceDetailMap.put(dataSourceBeanName,
                        new Status(Status.UNKNOWN.getCode(), e.getMessage()));
            }
        }

        // If Dashboard and DataSource are both OK, the health status is UP
        if (dashboardUp && dataSourceUp) {
            builder.up().withDetails(detailMap);
        }
        else {
            builder.unknown().withDetails(detailMap);
        }
    }

}

View Code

注入容器

        @Bean
    @ConditionalOnMissingBean
    @ConditionalOnEnabledHealthIndicator("sentinel") //management.health.sentinel.enabled=false 可禁用
    public SentinelHealthIndicator sentinelHealthIndicator(
            DefaultListableBeanFactory beanFactory,
            SentinelProperties sentinelProperties) {
        return new SentinelHealthIndicator(beanFactory, sentinelProperties);
    }

访问CURL端点

image

 初始化原理

1、初始化HealthIndicatorRegistry

org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration#healthIndicatorRegistry

 @Bean
    @ConditionalOnMissingBean({HealthIndicatorRegistry.class})
    public HealthIndicatorRegistry healthIndicatorRegistry(ApplicationContext applicationContext) {
    //内部会从容器获取HealthIndicator实现类 里面就有我们的sentinel实现类
        return HealthIndicatorRegistryBeans.get(applicationContext);
    }

2、org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorRegistryBeans#get

    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", (ClassLoader)null)) {
            (new ReactiveHealthIndicators()).get(applicationContext).forEach(indicators::putIfAbsent);
        }

        HealthIndicatorRegistryFactory factory = new HealthIndicatorRegistryFactory();
        //构建 HealthIndicatorRegistry
        return factory.createHealthIndicatorRegistry(indicators);
    }

3、返回含有所有health健康检查的 registry

     public HealthIndicatorRegistry createHealthIndicatorRegistry(
            Map<String, HealthIndicator> healthIndicators) {
        Assert.notNull(healthIndicators, "HealthIndicators must not be null");
        //初始化
        return initialize(new DefaultHealthIndicatorRegistry(), healthIndicators);
    }

    protected <T extends HealthIndicatorRegistry> T initialize(T registry,
            Map<String, HealthIndicator> healthIndicators) {
        for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
        //这里主要是获取bean的名字 截取掉 如 sentinelHealthIndicator  截取掉HealthIndicator  name为sentinel
            String name = this.healthIndicatorNameFactory.apply(entry.getKey());
            registry.register(name, entry.getValue());
        }
        return registry;
    }

执行原理

1、actor模式会在Spring MVC注册一个mappring入口为

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

->

org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.ServletWebOperationAdapter#handle

->

org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation#invoke

->

org.springframework.boot.actuate.health.HealthEndpointWebExtension#health

->

org.springframework.boot.actuate.health.HealthEndpointWebExtension#health

     @ReadOperation
    public WebEndpointResponse<Health> health(SecurityContext securityContext) {
        //内部就是从 初始化的registry遍历所有的处理器获取检查结果
        return this.responseMapper.map(this.delegate.health(), securityContext);
    }

2、org.springframework.boot.actuate.health.HealthEndpoint#health

image

 3、org.springframework.boot.actuate.health.CompositeHealthIndicator#health

    @Override
    public Health health() {
        Map<String, Health> healths = new LinkedHashMap<>();
        for (Map.Entry<String, HealthIndicator> entry : this.registry.getAll()
                .entrySet()) {
                //遍历执行 获取结果
            healths.put(entry.getKey(), entry.getValue().health());
        }
        //进行聚合返回
        return this.aggregator.aggregate(healths);
    }