美文网首页
聊聊springboot的liveness及readiness

聊聊springboot的liveness及readiness

作者: go4it | 来源:发表于2023-10-23 09:27 被阅读0次

    本文主要研究一下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

          本文链接:https://www.haomeiwen.com/subject/jondidtx.html