actuator 中health这个endpoint的源码解剖

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18416057/article/details/83088507

       用过spring boot的都应该知道里面有一个actuator的starter,这个actuator其实非常有用,它提供了很多监控的endpoint,比如今天要讲的health,info。。。。最近在弄的spring boot admin2.0其实也是以这个jar为基础来做的

    今天我们来讲一下health的endpoint。首先说一下spring boot 1.x和spring boot 2.x是有一些不一样的地方的,首先2.x版本的endpoint的地址也有有变化的,在1.x版本链接的基础上加“actuator”,以及想eureka jar的名称也不一样,配置也有些地方不一样,这些都是要注意的,如果你要从spring boot 1.x切换2.x

    现在回归主题,来解剖一下这个health的endpoint

  首先看一下入口HealthEndpoint这个类

标记1

这是actuator中提供大家实现自定义endpoint的注解,@endpoint也就是类似于@Controller,@ReadOperation, @WriteOperation, @DeleteOperation注解,分别对应生成Get/Post/Delete的Mapping

标记2

项目启动初始化HealthEndpoint中,属性healthIndicator被赋予CompositeHealthIndicator类,当我们访问health时,就会执行CompositeHealthIndicator的health方法

扫描二维码关注公众号,回复: 5521517 查看本文章

接下来看一下CompositeHealthIndicator类的health方法(看代码的注解)

#根据Spring boot的自动装配,根据相应的条件有没有满足,去加载各种的Indicator
 public void addHealthIndicator(String name, HealthIndicator indicator) {
        this.indicators.put(name, indicator);
    }
#循环调用之前收集到的Indicator中的health方法,将结果集放在
#一个map里面

    public Health health() {
        Map<String, Health> healths = new LinkedHashMap();
        Iterator var2 = this.indicators.entrySet().iterator();

        while(var2.hasNext()) {
            Entry<String, HealthIndicator> entry = (Entry)var2.next();
            healths.put(entry.getKey(), ((HealthIndicator)entry.getValue()).health());
        }
#执行healthAggregator的聚合方法,将上一步拿到的结果集map聚合到一个总的结果
        return this.healthAggregator.aggregate(healths);
    }

HealthIndicator的类结构大致如下(简单粗滤的画了一下,还有很多其他相关类没有画出)

然后再看看这个aggregate(聚合)方法代码,先附上关于healthAggregator的uml

先看AbstractHealthAggregator源码(讲解看注释):

public final Health aggregate(Map<String, Health> healths) {
#通过list.stream将status收集到一个list里面
        List<Status> statusCandidates = (List)healths.values().stream().map(Health::getStatus).collect(Collectors.toList());
 #将上一步拿到的list通过下面方法得到一个总的status       
Status status = this.aggregateStatus(statusCandidates);
        Map<String, Object> details = this.aggregateDetails(healths);
        return (new Builder(status, details)).build();
    }

    protected abstract Status aggregateStatus(List<Status> var1);

    protected Map<String, Object> aggregateDetails(Map<String, Health> healths) {
        return new LinkedHashMap(healths);
    }

再看this.aggregateStatus方法,AbstractHealthAggregator类中是抽象方法,没有具体的实现,所以要看具体的类OrderHealthAggregator

 public OrderedHealthAggregator() {
        this.setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN);
    }

    public void setStatusOrder(Status... statusOrder) {
        String[] order = new String[statusOrder.length];

        for(int i = 0; i < statusOrder.length; ++i) {
            order[i] = statusOrder[i].getCode();
        }

        this.setStatusOrder(Arrays.asList(order));
    }

    public void setStatusOrder(List<String> statusOrder) {
        Assert.notNull(statusOrder, "StatusOrder must not be null");
        this.statusOrder = statusOrder;
    }

    protected Status aggregateStatus(List<Status> candidates) {
        List<Status> filteredCandidates = new ArrayList();
        Iterator var3 = candidates.iterator();

#将传进来的list中的元素,跟statusorder比较是否是范围之内的元素,不是就剔除
        while(var3.hasNext()) {
            Status candidate = (Status)var3.next();
            if (this.statusOrder.contains(candidate.getCode())) {
                filteredCandidates.add(candidate);
            }
        }

        if (filteredCandidates.isEmpty()) {
            return Status.UNKNOWN;
        } else {
#将最终的list按照statusOrder的顺序排序,并将第一个取出
#排序的规则其实也是很简单,就是有down,就先取down,有OUT_OF_SERVICE就取OUT_OF_SERVICE

            filteredCandidates.sort(new OrderedHealthAggregator.StatusComparator(this.statusOrder));
            return (Status)filteredCandidates.get(0);
        }
    }

#排序的方法,实现Comparator,实现排序
    private class StatusComparator implements Comparator<Status> {
        private final List<String> statusOrder;

        StatusComparator(List<String> var1) {
            this.statusOrder = statusOrder;
        }
#按照statusOrder的顺序进行比较
        public int compare(Status s1, Status s2) {
            int i1 = this.statusOrder.indexOf(s1.getCode());
            int i2 = this.statusOrder.indexOf(s2.getCode());
            return i1 < i2 ? -1 : (i1 != i2 ? 1 : s1.getCode().compareTo(s2.getCode()));
        }
    }

最后最关键的点来了,有没有人会问,什么时候会去调用CompositeHealthIndicator的addHealthIndicator方法

关键看HealthEndpointAutoConfiguration 类

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

然后是HealthEndpointConfiguration类

@Configuration
class HealthEndpointConfiguration {
    HealthEndpointConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnEnabledEndpoint
    public HealthEndpoint healthEndpoint(ApplicationContext applicationContext) {
        return new HealthEndpoint(HealthIndicatorBeansComposite.get(applicationContext));
    }
}

最后是HealthIndicatorBeansComposite类get方法

public static HealthIndicator get(ApplicationContext applicationContext) {
        HealthAggregator healthAggregator = getHealthAggregator(applicationContext);
        Map<String, HealthIndicator> indicators = new LinkedHashMap();
#利用反射机制获取实现HealthIndicator类(以加载在容器的上下文中)
        indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class));
        if (ClassUtils.isPresent("reactor.core.publisher.Flux", (ClassLoader)null)) {
            (new HealthIndicatorBeansComposite.ReactiveHealthIndicators()).get(applicationContext).forEach(indicators::putIfAbsent);
        }

        CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory();        
        return factory.createHealthIndicator(healthAggregator, indicators);
    }

到这里我们清楚了,原来是CompositeHealthIndicatorFactory生产了一个 CompositeHealthIndicator以及入参是容器中的各种HealthIndicator类,到这里应该算是差不多了,如果有什么不对的地方大家可以提出来。这里虽然只介绍了health的,但可以举一反三,其它的endpoint也都差不多的

    其实这种源码看多了有很多东西是差不多写发的,有没有,哈哈

猜你喜欢

转载自blog.csdn.net/qq_18416057/article/details/83088507