深入了解Spring Boot2.3.0及以上版本的Liveness和Readiness功能
作者:codecraft
序
本文主要研究一下springboot的liveness及readiness
使用
management: endpoints: web: exposure: include: '*' endpoint: health: probes: enabled: true show-details: always health: # /actuator/health/liveness livenessState: enabled: true # /actuator/health/readiness readinessState: enabled: true
通过如上配置可以开启liveness及readiness,要求springboot版本在2.3.0及以上
ApplicationAvailabilityAutoConfiguration
org/springframework/boot/autoconfigure/availability/ApplicationAvailabilityAutoConfiguration.java
@Configuration(proxyBeanMethods = false) public class ApplicationAvailabilityAutoConfiguration { @Bean public ApplicationAvailabilityBean applicationAvailability() { return new ApplicationAvailabilityBean(); } }
ApplicationAvailabilityAutoConfiguration定义了ApplicationAvailabilityBean
ApplicationAvailabilityBean
org/springframework/boot/availability/ApplicationAvailabilityBean.java
public class ApplicationAvailabilityBean implements ApplicationAvailability, ApplicationListener<AvailabilityChangeEvent<?>> { private final Map<Class<? extends AvailabilityState>, AvailabilityChangeEvent<?>> events = new HashMap<>(); @Override public <S extends AvailabilityState> S getState(Class<S> stateType, S defaultState) { Assert.notNull(stateType, "StateType must not be null"); Assert.notNull(defaultState, "DefaultState must not be null"); S state = getState(stateType); return (state != null) ? state : defaultState; } @Override public <S extends AvailabilityState> S getState(Class<S> stateType) { AvailabilityChangeEvent<S> event = getLastChangeEvent(stateType); return (event != null) ? event.getState() : null; } @Override @SuppressWarnings("unchecked") public <S extends AvailabilityState> AvailabilityChangeEvent<S> getLastChangeEvent(Class<S> stateType) { return (AvailabilityChangeEvent<S>) this.events.get(stateType); } @Override public void onApplicationEvent(AvailabilityChangeEvent<?> event) { Class<? extends AvailabilityState> stateType = getStateType(event.getState()); this.events.put(stateType, event); } @SuppressWarnings("unchecked") private Class<? extends AvailabilityState> getStateType(AvailabilityState state) { if (state instanceof Enum) { return (Class<? extends AvailabilityState>) ((Enum<?>) state).getDeclaringClass(); } return state.getClass(); } }
ApplicationAvailabilityBean实现了ApplicationAvailability、ApplicationListener接口,它接收AvailabilityChangeEvent事件,然后存储到events中,getState方法则从events中获取指定class类型的AvailabilityState
AvailabilityChangeEvent
org/springframework/boot/availability/AvailabilityChangeEvent.java
public class AvailabilityChangeEvent<S extends AvailabilityState> extends PayloadApplicationEvent<S> { /** * Create a new {@link AvailabilityChangeEvent} instance. * @param source the source of the event * @param state the availability state (never {@code null}) */ public AvailabilityChangeEvent(Object source, S state) { super(source, state); } /** * Return the changed availability state. * @return the availability state */ public S getState() { return getPayload(); } @Override public ResolvableType getResolvableType() { return ResolvableType.forClassWithGenerics(getClass(), getStateType()); } private Class<?> getStateType() { S state = getState(); if (state instanceof Enum) { return ((Enum<?>) state).getDeclaringClass(); } return state.getClass(); } /** * Convenience method that can be used to publish an {@link AvailabilityChangeEvent} * to the given application context. * @param <S> the availability state type * @param context the context used to publish the event * @param state the changed availability state */ public static <S extends AvailabilityState> void publish(ApplicationContext context, S state) { Assert.notNull(context, "Context must not be null"); publish(context, context, state); } /** * Convenience method that can be used to publish an {@link AvailabilityChangeEvent} * to the given application context. * @param <S> the availability state type * @param publisher the publisher used to publish the event * @param source the source of the event * @param state the changed availability state */ public static <S extends AvailabilityState> void publish(ApplicationEventPublisher publisher, Object source, S state) { Assert.notNull(publisher, "Publisher must not be null"); publisher.publishEvent(new AvailabilityChangeEvent<>(source, state)); } }
AvailabilityChangeEvent继承了PayloadApplicationEvent,它还定义了publish方法
AvailabilityHealthContributorAutoConfiguration
org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfiguration.java
@Configuration(proxyBeanMethods = false) @AutoConfigureAfter(ApplicationAvailabilityAutoConfiguration.class) public class AvailabilityHealthContributorAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "livenessStateHealthIndicator") @ConditionalOnProperty(prefix = "management.health.livenessstate", name = "enabled", havingValue = "true") public LivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) { return new LivenessStateHealthIndicator(applicationAvailability); } @Bean @ConditionalOnMissingBean(name = "readinessStateHealthIndicator") @ConditionalOnProperty(prefix = "management.health.readinessstate", name = "enabled", havingValue = "true") public ReadinessStateHealthIndicator readinessStateHealthIndicator( ApplicationAvailability applicationAvailability) { return new ReadinessStateHealthIndicator(applicationAvailability); } }
AvailabilityHealthContributorAutoConfiguration定义了LivenessStateHealthIndicator、ReadinessStateHealthIndicator
AvailabilityStateHealthIndicator
org/springframework/boot/actuate/availability/AvailabilityStateHealthIndicator.java
public class AvailabilityStateHealthIndicator extends AbstractHealthIndicator { private final ApplicationAvailability applicationAvailability; private Class<? extends AvailabilityState> stateType; private final Map<AvailabilityState, Status> statusMappings = new HashMap<>(); /** * Create a new {@link AvailabilityStateHealthIndicator} instance. * @param <S> the availability state type * @param applicationAvailability the application availability * @param stateType the availability state type * @param statusMappings consumer used to setup the status mappings */ public <S extends AvailabilityState> AvailabilityStateHealthIndicator( ApplicationAvailability applicationAvailability, Class<S> stateType, Consumer<StatusMappings<S>> statusMappings) { Assert.notNull(applicationAvailability, "ApplicationAvailability must not be null"); Assert.notNull(stateType, "StateType must not be null"); Assert.notNull(statusMappings, "StatusMappings must not be null"); this.applicationAvailability = applicationAvailability; this.stateType = stateType; statusMappings.accept(this.statusMappings::put); assertAllEnumsMapped(stateType); } @SuppressWarnings({ "unchecked", "rawtypes" }) private <S extends AvailabilityState> void assertAllEnumsMapped(Class<S> stateType) { if (!this.statusMappings.containsKey(null) && Enum.class.isAssignableFrom(stateType)) { EnumSet elements = EnumSet.allOf((Class) stateType); for (Object element : elements) { Assert.isTrue(this.statusMappings.containsKey(element), () -> "StatusMappings does not include " + element); } } } @Override protected void doHealthCheck(Builder builder) throws Exception { AvailabilityState state = getState(this.applicationAvailability); Status status = this.statusMappings.get(state); if (status == null) { status = this.statusMappings.get(null); } Assert.state(status != null, () -> "No mapping provided for " + state); builder.status(status); } /** * Return the current availability state. Subclasses can override this method if a * different retrieval mechanism is needed. * @param applicationAvailability the application availability * @return the current availability state */ protected AvailabilityState getState(ApplicationAvailability applicationAvailability) { return applicationAvailability.getState(this.stateType); } /** * Callback used to add status mappings. * * @param <S> the availability state type */ public interface StatusMappings<S extends AvailabilityState> { /** * Add the status that should be used if no explicit mapping is defined. * @param status the default status */ default void addDefaultStatus(Status status) { add(null, status); } /** * Add a new status mapping . * @param availabilityState the availability state * @param status the mapped status */ void add(S availabilityState, Status status); } }
AvailabilityStateHealthIndicator继承了AbstractHealthIndicator,它定义了statusMappings,key为AvailabilityState,value为Status,其doHealthCheck就是获取state,然后从statusMappings取出对应的status
LivenessStateHealthIndicator
org/springframework/boot/actuate/availability/LivenessStateHealthIndicator.java
public class LivenessStateHealthIndicator extends AvailabilityStateHealthIndicator { public LivenessStateHealthIndicator(ApplicationAvailability availability) { super(availability, LivenessState.class, (statusMappings) -> { statusMappings.add(LivenessState.CORRECT, Status.UP); statusMappings.add(LivenessState.BROKEN, Status.DOWN); }); } @Override protected AvailabilityState getState(ApplicationAvailability applicationAvailability) { return applicationAvailability.getLivenessState(); } }
LivenessStateHealthIndicator继承了AvailabilityStateHealthIndicator,它建立了LivenessState.CORRECT到Status.UP,LivenessState.BROKEN到Status.DOWN的映射
ReadinessStateHealthIndicator
org/springframework/boot/actuate/availability/ReadinessStateHealthIndicator.java
public class ReadinessStateHealthIndicator extends AvailabilityStateHealthIndicator { public ReadinessStateHealthIndicator(ApplicationAvailability availability) { super(availability, ReadinessState.class, (statusMappings) -> { statusMappings.add(ReadinessState.ACCEPTING_TRAFFIC, Status.UP); statusMappings.add(ReadinessState.REFUSING_TRAFFIC, Status.OUT_OF_SERVICE); }); } @Override protected AvailabilityState getState(ApplicationAvailability applicationAvailability) { return applicationAvailability.getReadinessState(); } }
ReadinessStateHealthIndicator继承了AvailabilityStateHealthIndicator,它定义了ReadinessState.ACCEPTING_TRAFFIC到Status.UP,ReadinessState.REFUSING_TRAFFIC到Status.OUT_OF_SERVICE的映射
EventPublishingRunListener
org/springframework/boot/context/event/EventPublishingRunListener.java
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { @Override public void started(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context)); AvailabilityChangeEvent.publish(context, LivenessState.CORRECT); } @Override public void running(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context)); AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC); } }
EventPublishingRunListener的started方法会发布AvailabilityChangeEvent,其state为LivenessState.CORRECT;running方法会发布AvailabilityChangeEvent,其state为ReadinessState.ACCEPTING_TRAFFIC
SpringApplicationRunListeners
org/springframework/boot/SpringApplicationRunListeners.java
class SpringApplicationRunListeners { void started(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.started(context); } } void running(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.running(context); } } //...... }
SpringApplicationRunListeners的started会回调listener的started,running会回调listener的running方法
ServletWebServerApplicationContext
org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java
public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext { @Override protected void doClose() { if (isActive()) { AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC); } super.doClose(); } //...... }
ServletWebServerApplicationContext的doClose方法在active的时候会发布AvailabilityChangeEvent,state为ReadinessState.REFUSING_TRAFFIC
SpringApplication
org/springframework/boot/SpringApplication.java
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
SpringApplication的run方法会先获取SpringApplicationRunListeners,然后执行listeners.starting(),接着prepareEnvironment、createApplicationContext、prepareContext、refreshContext、afterRefresh;之后执行listeners.started(context);再执行listeners.running(context)
小结
AvailabilityHealthContributorAutoConfiguration定义了LivenessStateHealthIndicator、ReadinessStateHealthIndicator,它们依赖AvailabilityChangeEvent,SpringApplication的run方法会先后触发listeners.starting()、listeners.started(context)、listeners.running(context);EventPublishingRunListener的started方法会发布AvailabilityChangeEvent,其state为LivenessState.CORRECT;running方法会发布AvailabilityChangeEvent,其state为ReadinessState.ACCEPTING_TRAFFIC。
以上就是springboot的liveness及readiness的详细内容,更多关于springboot liveness readiness的资料请关注脚本之家其它相关文章!