• 聊聊springboot的liveness及readiness


    本文主要研究一下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      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    通过如上配置可以开启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();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ApplicationAvailabilityAutoConfiguration定义了ApplicationAvailabilityBean

    ApplicationAvailabilityBean

    org/springframework/boot/availability/ApplicationAvailabilityBean.java

    public class ApplicationAvailabilityBean
    		implements ApplicationAvailability, ApplicationListener> {
    
    	private final Map, AvailabilityChangeEvent> events = new HashMap<>();
    
    	@Override
    	public  S getState(Class 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 getState(Class stateType) {
    		AvailabilityChangeEvent event = getLastChangeEvent(stateType);
    		return (event != null) ? event.getState() : null;
    	}
    
    	@Override
    	@SuppressWarnings("unchecked")
    	public  AvailabilityChangeEvent getLastChangeEvent(Class stateType) {
    		return (AvailabilityChangeEvent) this.events.get(stateType);
    	}
    
    	@Override
    	public void onApplicationEvent(AvailabilityChangeEvent event) {
    		Class stateType = getStateType(event.getState());
    		this.events.put(stateType, event);
    	}
    
    	@SuppressWarnings("unchecked")
    	private Class getStateType(AvailabilityState state) {
    		if (state instanceof Enum) {
    			return (Class) ((Enum) state).getDeclaringClass();
    		}
    		return state.getClass();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    ApplicationAvailabilityBean实现了ApplicationAvailability、ApplicationListener接口,它接收AvailabilityChangeEvent事件,然后存储到events中,getState方法则从events中获取指定class类型的AvailabilityState

    AvailabilityChangeEvent

    org/springframework/boot/availability/AvailabilityChangeEvent.java

    public class AvailabilityChangeEvent extends PayloadApplicationEvent {
    
    	/**
    	 * 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  the availability state type
    	 * @param context the context used to publish the event
    	 * @param state the changed availability state
    	 */
    	public static  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  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  void publish(ApplicationEventPublisher publisher, Object source,
    			S state) {
    		Assert.notNull(publisher, "Publisher must not be null");
    		publisher.publishEvent(new AvailabilityChangeEvent<>(source, state));
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    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);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    AvailabilityHealthContributorAutoConfiguration定义了LivenessStateHealthIndicator、ReadinessStateHealthIndicator

    AvailabilityStateHealthIndicator

    org/springframework/boot/actuate/availability/AvailabilityStateHealthIndicator.java

    public class AvailabilityStateHealthIndicator extends AbstractHealthIndicator {
    
    	private final ApplicationAvailability applicationAvailability;
    
    	private Class stateType;
    
    	private final Map statusMappings = new HashMap<>();
    
    	/**
    	 * Create a new {@link AvailabilityStateHealthIndicator} instance.
    	 * @param  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  AvailabilityStateHealthIndicator(
    			ApplicationAvailability applicationAvailability, Class stateType,
    			Consumer> 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  void assertAllEnumsMapped(Class 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  the availability state type
    	 */
    	public interface StatusMappings {
    
    		/**
    		 * 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);
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    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();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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);
    		}
    	}
    
    	//......
    }	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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();
    	}
    
    	//......
    }	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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 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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    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。

  • 相关阅读:
    让您了解GPS北斗卫星时间同步系统(NTP时钟同步)重要性
    初识jdbc
    element-ui upload图片上传组件使用
    软考45-上午题-【数据库】-数据操纵语言DML
    Vue源码阅读:createApp的过程(三)
    (22)STM32——RTC时钟笔记(基于正点原子探索者)
    pandas plot函数:数据可视化的快捷通道
    paddle 44 用onnxruntime实现ppyoloe模型的部署(含python和c++版本),支持batchsize
    JVM篇---第七篇
    如何在 Windows 中卸载 SQL Server?
  • 原文地址:https://blog.csdn.net/hello_ejb3/article/details/134004413