本文主要研究一下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及以上
org/springframework/boot/autoconfigure/availability/ApplicationAvailabilityAutoConfiguration.java
@Configuration(proxyBeanMethods = false)
public class ApplicationAvailabilityAutoConfiguration {
@Bean
public ApplicationAvailabilityBean applicationAvailability() {
return new ApplicationAvailabilityBean();
}
}
ApplicationAvailabilityAutoConfiguration定义了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 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
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));
}
}
AvailabilityChangeEvent继承了PayloadApplicationEvent,它还定义了publish方法
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
org/springframework/boot/actuate/availability/AvailabilityStateHealthIndicator.java
public class AvailabilityStateHealthIndicator extends AbstractHealthIndicator {
private final ApplicationAvailability applicationAvailability;
private Class extends AvailabilityState> 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);
}
}
AvailabilityStateHealthIndicator继承了AbstractHealthIndicator,它定义了statusMappings,key为AvailabilityState,value为Status,其doHealthCheck就是获取state,然后从statusMappings取出对应的status
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的映射
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的映射
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
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方法
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
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;
}
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。