日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

詳解SpringBoot健康檢查的實現原理

瀏覽:84日期:2023-03-21 13:15:37

SpringBoot自動裝配的套路,直接看 spring.factories 文件,當我們使用的時候只需要引入如下依賴

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

然后在 org.springframework.boot.spring-boot-actuator-autoconfigure 包下去就可以找到這個文件

自動裝配

查看這個文件發現引入了很多的配置類,這里先關注一下 XXXHealthIndicatorAutoConfiguration 系列的類,這里咱們拿第一個 RabbitHealthIndicatorAutoConfiguration 為例來解析一下。看名字就知道這個是RabbitMQ的健康檢查的自動配置類

@Configuration@ConditionalOnClass(RabbitTemplate.class)@ConditionalOnBean(RabbitTemplate.class)@ConditionalOnEnabledHealthIndicator('rabbit')@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)@AutoConfigureAfter(RabbitAutoConfiguration.class)public class RabbitHealthIndicatorAutoConfiguration extends CompositeHealthIndicatorConfiguration<RabbitHealthIndicator, RabbitTemplate> { private final Map<String, RabbitTemplate> rabbitTemplates; public RabbitHealthIndicatorAutoConfiguration( Map<String, RabbitTemplate> rabbitTemplates) { this.rabbitTemplates = rabbitTemplates; } @Bean @ConditionalOnMissingBean(name = 'rabbitHealthIndicator') public HealthIndicator rabbitHealthIndicator() { return createHealthIndicator(this.rabbitTemplates); }}

按照以往的慣例,先解析注解

@ConditionalOnXXX 系列又出現了,前兩個就是說如果當前存在 RabbitTemplate 這個bean也就是說我們的項目中使用到了RabbitMQ才能進行下去 @ConditionalOnEnabledHealthIndicator 這個注解很明顯是SpringBoot actuator自定義的注解,看一下吧

@Conditional(OnEnabledHealthIndicatorCondition.class)public @interface ConditionalOnEnabledHealthIndicator { String value();}class OnEnabledHealthIndicatorCondition extends OnEndpointElementCondition { OnEnabledHealthIndicatorCondition() { super('management.health.', ConditionalOnEnabledHealthIndicator.class); }}public abstract class OnEndpointElementCondition extends SpringBootCondition { private final String prefix; private final Class<? extends Annotation> annotationType; protected OnEndpointElementCondition(String prefix, Class<? extends Annotation> annotationType) { this.prefix = prefix; this.annotationType = annotationType; } @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { AnnotationAttributes annotationAttributes = AnnotationAttributes .fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); String endpointName = annotationAttributes.getString('value'); ConditionOutcome outcome = getEndpointOutcome(context, endpointName); if (outcome != null) { return outcome; } return getDefaultEndpointsOutcome(context); } protected ConditionOutcome getEndpointOutcome(ConditionContext context, String endpointName) { Environment environment = context.getEnvironment(); String enabledProperty = this.prefix + endpointName + '.enabled'; if (environment.containsProperty(enabledProperty)) { boolean match = environment.getProperty(enabledProperty, Boolean.class, true); return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType).because( this.prefix + endpointName + '.enabled is ' + match)); } return null; } protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) { boolean match = Boolean.valueOf(context.getEnvironment() .getProperty(this.prefix + 'defaults.enabled', 'true')); return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType).because( this.prefix + 'defaults.enabled is considered ' + match)); }}public abstract class SpringBootCondition implements Condition { private final Log logger = LogFactory.getLog(getClass()); @Override public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String classOrMethodName = getClassOrMethodName(metadata); try { ConditionOutcome outcome = getMatchOutcome(context, metadata); logOutcome(classOrMethodName, outcome); recordEvaluation(context, classOrMethodName, outcome); return outcome.isMatch(); } catch (NoClassDefFoundError ex) { throw new IllegalStateException( 'Could not evaluate condition on ' + classOrMethodName + ' due to ' + ex.getMessage() + ' not ' + 'found. Make sure your own configuration does not rely on ' + 'that class. This can also happen if you are ' + '@ComponentScanning a springframework package (e.g. if you ' + 'put a @ComponentScan in the default package by mistake)', ex); } catch (RuntimeException ex) { throw new IllegalStateException( 'Error processing condition on ' + getName(metadata), ex); } } private void recordEvaluation(ConditionContext context, String classOrMethodName, ConditionOutcome outcome) { if (context.getBeanFactory() != null) { ConditionEvaluationReport.get(context.getBeanFactory()) .recordConditionEvaluation(classOrMethodName, this, outcome); } }}

上方的入口方法是 SpringBootCondition 類的 matches 方法, getMatchOutcome 這個方法則是子類 OnEndpointElementCondition 的,這個方法首先會去環境變量中查找是否存在 management.health.rabbit.enabled 屬性,如果沒有的話則去查找 management.health.defaults.enabled 屬性,如果這個屬性還沒有的話則設置默認值為true

當這里返回true時整個 RabbitHealthIndicatorAutoConfiguration 類的自動配置才能繼續下去

@AutoConfigureBefore 既然這樣那就先看看類 HealthIndicatorAutoConfiguration 都是干了啥再回來吧

@Configuration@EnableConfigurationProperties({ HealthIndicatorProperties.class })public class HealthIndicatorAutoConfiguration { private final HealthIndicatorProperties properties; public HealthIndicatorAutoConfiguration(HealthIndicatorProperties properties) { this.properties = properties; } @Bean @ConditionalOnMissingBean({ HealthIndicator.class, ReactiveHealthIndicator.class }) public ApplicationHealthIndicator applicationHealthIndicator() { return new ApplicationHealthIndicator(); } @Bean @ConditionalOnMissingBean(HealthAggregator.class) public OrderedHealthAggregator healthAggregator() { OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator(); if (this.properties.getOrder() != null) { healthAggregator.setStatusOrder(this.properties.getOrder()); } return healthAggregator; }}

首先這個類引入了配置文件 HealthIndicatorProperties 這個配置類是系統狀態相關的配置

@ConfigurationProperties(prefix = 'management.health.status')public class HealthIndicatorProperties { private List<String> order = null; private final Map<String, Integer> httpMapping = new HashMap<>();}

接著就是注冊了2個bean ApplicationHealthIndicator 和 OrderedHealthAggregator 這兩個bean的作用稍后再說,現在回到 RabbitHealthIndicatorAutoConfiguration 類

@AutoConfigureAfterHealthIndicatorpublic abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndicator, S> { @Autowired private HealthAggregator healthAggregator; protected HealthIndicator createHealthIndicator(Map<String, S> beans) { if (beans.size() == 1) { return createHealthIndicator(beans.values().iterator().next()); } CompositeHealthIndicator composite = new CompositeHealthIndicator( this.healthAggregator); for (Map.Entry<String, S> entry : beans.entrySet()) { composite.addHealthIndicator(entry.getKey(), createHealthIndicator(entry.getValue())); } return composite; } @SuppressWarnings('unchecked') protected H createHealthIndicator(S source) { Class<?>[] generics = ResolvableType .forClass(CompositeHealthIndicatorConfiguration.class, getClass()) .resolveGenerics(); Class<H> indicatorClass = (Class<H>) generics[0]; Class<S> sourceClass = (Class<S>) generics[1]; try { return indicatorClass.getConstructor(sourceClass).newInstance(source); } catch (Exception ex) { throw new IllegalStateException('Unable to create indicator ' + indicatorClass + ' for source ' + sourceClass, ex); } }} 首先這里注入了一個對象 HealthAggregator ,這個對象就是剛才注冊的 OrderedHealthAggregator 第一個 createHealthIndicator 方法執行邏輯為:如果傳入的beans的size 為1,則調用 createHealthIndicator 創建 HealthIndicator 否則創建 CompositeHealthIndicator ,遍歷傳入的beans,依次創建 HealthIndicator ,加入到 CompositeHealthIndicator 中 第二個 createHealthIndicator 的執行邏輯為:獲得 CompositeHealthIndicatorConfiguration 中的泛型參數根據泛型參數H對應的class和S對應的class,在H對應的class中找到聲明了參數為S類型的構造器進行實例化 最后這里創建出來的bean為 RabbitHealthIndicator 回憶起之前學習健康檢查的使用時,如果我們需要自定義健康檢查項時一般的操作都是實現 HealthIndicator 接口,由此可以猜測 RabbitHealthIndicator 應該也是這樣做的。觀察這個類的繼承關系可以發現這個類繼承了一個實現實現此接口的類 AbstractHealthIndicator ,而RabbitMQ的監控檢查流程則如下代碼所示

//這個方法是AbstractHealthIndicator的public final Health health() { Health.Builder builder = new Health.Builder(); try { doHealthCheck(builder); } catch (Exception ex) { if (this.logger.isWarnEnabled()) { String message = this.healthCheckFailedMessage.apply(ex); this.logger.warn(StringUtils.hasText(message) ? message : DEFAULT_MESSAGE, ex); } builder.down(ex); } return builder.build(); }//下方兩個方法是由類RabbitHealthIndicator實現的protected void doHealthCheck(Health.Builder builder) throws Exception { builder.up().withDetail('version', getVersion()); } private String getVersion() { return this.rabbitTemplate.execute((channel) -> channel.getConnection() .getServerProperties().get('version').toString()); }健康檢查

上方一系列的操作之后,其實就是搞出了一個RabbitMQ的 HealthIndicator 實現類,而負責檢查RabbitMQ健康不健康也是這個類來負責的。由此我們可以想象到如果當前環境存在MySQL、Redis、ES等情況應該也是這么個操作

那么接下來無非就是當有調用方訪問如下地址時,分別調用整個系統的所有的 HealthIndicator 的實現類的 health 方法即可了

http://ip:port/actuator/health

HealthEndpointAutoConfiguration

上邊說的這個操作過程就在類 HealthEndpointAutoConfiguration 中,這個配置類同樣也是在 spring.factories 文件中引入的

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

這里重點的地方在于引入的 HealthEndpointConfiguration 這個類

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

這個類只是構建了一個類 HealthEndpoint ,這個類我們可以理解為一個SpringMVC的Controller,也就是處理如下請求的

http://ip:port/actuator/health

那么首先看一下它的構造方法傳入的是個啥對象吧

public static HealthIndicator get(ApplicationContext applicationContext) { HealthAggregator healthAggregator = getHealthAggregator(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); } CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory(); return factory.createHealthIndicator(healthAggregator, indicators); }

跟我們想象中的一樣,就是通過Spring容器獲取所有的 HealthIndicator 接口的實現類,我這里只有幾個默認的和RabbitMQ

詳解SpringBoot健康檢查的實現原理

然后都放入了其中一個聚合的實現類 CompositeHealthIndicator 中

既然 HealthEndpoint構建好了,那么只剩下最后一步處理請求了

@Endpoint(id = 'health')public class HealthEndpoint { private final HealthIndicator healthIndicator; @ReadOperation public Health health() { return this.healthIndicator.health(); }}

剛剛我們知道,這個類是通過 CompositeHealthIndicator 構建的,所以 health 方法的實現就在這個類中

public Health health() { Map<String, Health> healths = new LinkedHashMap<>(); for (Map.Entry<String, HealthIndicator> entry : this.indicators.entrySet()) { //循環調用 healths.put(entry.getKey(), entry.getValue().health()); } //對結果集排序 return this.healthAggregator.aggregate(healths); }

至此SpringBoot的健康檢查實現原理全部解析完成

以上就是詳解SpringBoot健康檢查的實現原理的詳細內容,更多關于SpringBoot健康檢查實現原理的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产欧美日韩一区二区三区在线| 亚洲永久精品唐人导航网址| av最新在线| aa亚洲婷婷| 日韩理论片av| 国产精品成人一区二区网站软件| 欧美精品黄色| 国产成人免费精品| 国产精品v日韩精品v欧美精品网站 | 18国产精品| 一区二区自拍| 久久精品国产68国产精品亚洲| 亚洲精品在线二区| 久久在线免费| 99热精品久久| 亚洲性视频h| 香蕉久久99| 欧美激情国产在线| 天堂va在线高清一区| 老牛影视精品| 日本在线视频一区二区| 快播电影网址老女人久久| 日韩高清在线观看一区二区| 日韩在线黄色| 好看的av在线不卡观看| 色老板在线视频一区二区| 美女精品视频在线| 久久精品理论片| 中文字幕在线视频网站| 激情视频网站在线播放色| av中文资源在线资源免费观看| 国产精品久久久免费| 国产精品国产三级在线观看| 日韩精品一区二区三区中文| 免费人成在线不卡| 亚洲免费中文| 国产日产精品_国产精品毛片| 91免费精品国偷自产在线在线| 中文字幕一区二区三区四区久久| 综合激情在线| 国产欧美日韩一区二区三区四区| 久久精品av麻豆的观看方式| 久久三级毛片| 狠狠操综合网| 日本欧美一区二区| 国内精品伊人| 久久精品国产大片免费观看| 黄色亚洲精品| 99视频一区| 好吊日精品视频 | 日韩av在线免费观看不卡| 国产精品嫩草99av在线| 自拍日韩欧美| 中文字幕成人| 丰满少妇一区| 麻豆精品91| 国产一区二区三区四区五区传媒| 久久国产直播| 久久国产精品久久w女人spa| 中文字幕av一区二区三区人| 日日摸夜夜添夜夜添国产精品| 亚洲视频二区| 欧美日韩国产综合网| 天堂成人国产精品一区| 亚洲一区二区三区四区电影| 久久国产尿小便嘘嘘| 日韩精品不卡一区二区| 欧美激情视频一区二区三区在线播放| 肉色欧美久久久久久久免费看 | 精品国产精品久久一区免费式 | 免费成人在线观看| 久久久精品国产**网站| 欧美在线亚洲| 国内精品麻豆美女在线播放视频| 欧美福利专区| 欧美91在线| 久久国产欧美日韩精品| 免费日韩av片| 亚洲国产日韩欧美在线| 久久不卡国产精品一区二区| 亚洲免费影院| 亚洲精品99| 欧美日韩视频网站| 麻豆国产精品| 夜久久久久久| 国产99亚洲| 日韩在线看片| 国产精品成人自拍| 日韩精品一二区| 久久亚洲二区| 午夜视频一区二区在线观看| 在线成人直播| 亚洲国产不卡| 亚洲手机视频| 亚洲神马久久| 久久99久久久精品欧美| 国产伦一区二区三区| 亚洲日本在线观看视频| 蜜桃91丨九色丨蝌蚪91桃色 | 国产精品男女| 高清一区二区三区| 国内精品伊人| 亚洲五月婷婷| 日本中文字幕一区二区视频| 日本色综合中文字幕| 精品中文字幕一区二区三区四区| 国产精品va| 国产在线观看www| 亚洲综合国产| 国产亚洲观看| 亚洲网站视频| 日韩精品一区二区三区中文 | 欧美精选一区二区三区| 亚洲激情国产| 国产精品一区二区精品| 久久久久.com| 亚洲一级大片| 久久精品国产99久久| 免费在线观看不卡| 老牛影视精品| 蜜臀国产一区二区三区在线播放| 国产探花在线精品一区二区| 久久婷婷av| 国产亚洲福利| 国产一区二区三区黄网站 | 一区二区三区午夜视频| 91一区二区三区四区| 麻豆精品99| 国产另类在线| 国产精品一线| 91免费精品国偷自产在线在线| 亚洲精选久久| 亚洲精品九九| 日韩1区2区日韩1区2区| 国产精品调教视频| 777久久精品| 欧美91在线|欧美| 欧美激情另类| 欧美成a人片免费观看久久五月天| 日韩av影院| 欧美国产专区| 国产欧美一区二区三区精品酒店| 美女av一区| 深夜福利视频一区二区| 色综合www| 一本一道久久a久久精品蜜桃| 欧美日韩国产高清| 久久午夜影视| 国产精品欧美三级在线观看| 成人在线黄色| 婷婷综合社区| 亚洲三区欧美一区国产二区| 亚洲精品高潮| 精品视频自拍| 亚洲精品一区二区妖精| 日韩国产一二三区| 精品免费av一区二区三区| 99热精品久久| 国产欧美日韩一区二区三区四区| 久久久久久一区二区| 国产女优一区| 精品欧美视频| 久久国产66| 久久毛片亚洲| 久久夜色精品| 麻豆精品在线| 中文字幕免费一区二区| 岛国av在线网站| 麻豆精品91| av免费不卡国产观看| 蜜臀va亚洲va欧美va天堂| 久久中文字幕一区二区三区| 视频一区二区中文字幕| 欧美freesex黑人又粗又大| 久久精品999| 日韩极品在线观看| 在线视频日韩| 91精品一区二区三区综合| 国产极品模特精品一二| 日韩精品一区二区三区中文在线 | 理论片午夜视频在线观看| 欧美日一区二区三区在线观看国产免 | 日韩欧美在线中字| 久久精品av麻豆的观看方式| 日韩在线一区二区| av在线最新| 精品资源在线| 国产精品久久久久9999高清| 日韩国产一二三区| 亚洲一区导航| 一本综合精品| 日韩区一区二| 日韩专区欧美专区| 黄色日韩精品| 香蕉成人久久| 亚洲一区欧美二区| 另类激情亚洲| 亚洲一区成人| 午夜亚洲福利| 中文字幕亚洲精品乱码|