文章目录

  • 一、认识Actuator
  • 1、回顾Actuator
  • 2、Actuator重要端点
  • 二、源码分析
  • 1、Endpoint自动装配
  • (1)自动配置入口
  • (2)普通Endpoint自动装配
  • (3)配置Web - Endpoint
  • (4)注册Endpoint为Mvc映射
  • 2、BeansEndpoint自动装配原理
  • (1)自动装配类
  • (2)BeansEndpoint
  • (3)执行结果
  • 3、MappingsEndpoint自动装配原理
  • (1)自动装配类
  • (2)MappingsEndpoint
  • (3)执行结果
  • 4、ShutdownEndpoint自动装配原理
  • (1)自动装配类
  • (2)ShutdownEndpoint


一、认识Actuator

1、回顾Actuator

Actuator是Springboot提供运行时数据交互的规范。
它覆盖应用内心戏、环境配置、度量指标、敏感操作。
交互方式为Http Web或者JMX。

Spring Boot Actuator ——健康检查神器

2、Actuator重要端点

Springboot应用执行器Actuator源码分析_后端

二、源码分析

1、Endpoint自动装配

(1)自动配置入口

Springboot应用执行器Actuator源码分析_自动装配_02

(2)普通Endpoint自动装配

@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = EnvironmentEndpoint.class) // EnvironmentEndpoint可用
@EnableConfigurationProperties(EnvironmentEndpointProperties.class)// 构建属性配置文件
public class EnvironmentEndpointAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public EnvironmentEndpoint environmentEndpoint(Environment environment, EnvironmentEndpointProperties properties,
			ObjectProvider<SanitizingFunction> sanitizingFunctions) {
		EnvironmentEndpoint endpoint = new EnvironmentEndpoint(environment,
				sanitizingFunctions.orderedStream().collect(Collectors.toList()));
		String[] keysToSanitize = properties.getKeysToSanitize();
		if (keysToSanitize != null) {
			endpoint.setKeysToSanitize(keysToSanitize);
		}
		String[] additionalKeysToSanitize = properties.getAdditionalKeysToSanitize();
		if (additionalKeysToSanitize != null) {
			endpoint.keysToSanitize(additionalKeysToSanitize);
		}
		return endpoint;
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnBean(EnvironmentEndpoint.class)
	@ConditionalOnAvailableEndpoint(exposure = { EndpointExposure.WEB, EndpointExposure.CLOUD_FOUNDRY })
	public EnvironmentEndpointWebExtension environmentEndpointWebExtension(EnvironmentEndpoint environmentEndpoint) {
		return new EnvironmentEndpointWebExtension(environmentEndpoint);
	}

}

(3)配置Web - Endpoint

通过自动配置类WebEndpointAutoConfiguration进行自动装配。

// org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration#webEndpointDiscoverer
@Bean
@ConditionalOnMissingBean(WebEndpointsSupplier.class)
public WebEndpointDiscoverer webEndpointDiscoverer(ParameterValueMapper parameterValueMapper,
		EndpointMediaTypes endpointMediaTypes, ObjectProvider<PathMapper> endpointPathMappers,
		ObjectProvider<OperationInvokerAdvisor> invokerAdvisors,
		ObjectProvider<EndpointFilter<ExposableWebEndpoint>> filters) {
		// 把所有的Web - Endpoint都搜集到
	return new WebEndpointDiscoverer(this.applicationContext, parameterValueMapper, endpointMediaTypes,
			endpointPathMappers.orderedStream().collect(Collectors.toList()),
			invokerAdvisors.orderedStream().collect(Collectors.toList()),
			filters.orderedStream().collect(Collectors.toList()));
}

(4)注册Endpoint为Mvc映射

通过自动配置类WebMvcEndpointManagementContextConfiguration注册Endpoint为Mvc映射。

通过各种方式定义的Endpoint,创建为WebMvcEndpointHandlerMapping,进行Web映射。

// org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration#webEndpointServletHandlerMapping
@Bean
@ConditionalOnMissingBean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
		ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
		EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
		WebEndpointProperties webEndpointProperties, Environment environment) {
	List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
	Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
	allEndpoints.addAll(webEndpoints);
	allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
	allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
	String basePath = webEndpointProperties.getBasePath();
	EndpointMapping endpointMapping = new EndpointMapping(basePath);
	boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
	return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
			corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
			shouldRegisterLinksMapping, WebMvcAutoConfiguration.pathPatternParser);
}

2、BeansEndpoint自动装配原理

(1)自动装配类

@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = BeansEndpoint.class)
public class BeansEndpointAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public BeansEndpoint beansEndpoint(ConfigurableApplicationContext applicationContext) {
		// 创建一个BeansEndpoint
		return new BeansEndpoint(applicationContext);
	}

}

(2)BeansEndpoint

// id就是可以访问的web路径
@Endpoint(id = "beans")
public class BeansEndpoint {
// 读操作
@ReadOperation
public ApplicationBeans beans() {
	Map<String, ContextBeans> contexts = new HashMap<>();
	// 将所有容器都拿出来
	ConfigurableApplicationContext context = this.context;
	while (context != null) {
		// 将Bean都拿出来,封装成一个ContextBeans
		contexts.put(context.getId(), ContextBeans.describing(context));
		context = getConfigurableParent(context);
	}
	// 创建一个ApplicationBeans
	// 返回的信息就会json格式化到响应
	return new ApplicationBeans(contexts);
}
// 返回的对象
public static final class ApplicationBeans {

	private final Map<String, ContextBeans> contexts;

	private ApplicationBeans(Map<String, ContextBeans> contexts) {
		this.contexts = contexts;
	}

	public Map<String, ContextBeans> getContexts() {
		return this.contexts;
	}

}

(3)执行结果

Springboot应用执行器Actuator源码分析_java_03

3、MappingsEndpoint自动装配原理

(1)自动装配类

@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = MappingsEndpoint.class)
public class MappingsEndpointAutoConfiguration {

	// 配置Mapping
	@Bean
	public MappingsEndpoint mappingsEndpoint(ApplicationContext applicationContext,
			ObjectProvider<MappingDescriptionProvider> descriptionProviders) {
		return new MappingsEndpoint(descriptionProviders.orderedStream().collect(Collectors.toList()),
				applicationContext);
	}

	// 后面还有关于Servlet的相关配置,此处就先不看

(2)MappingsEndpoint

// web访问路径
@Endpoint(id = "mappings")
public class MappingsEndpoint {
// org.springframework.boot.actuate.web.mappings.MappingsEndpoint#mappings
@ReadOperation
public ApplicationMappings mappings() {
	ApplicationContext target = this.context;
	Map<String, ContextMappings> contextMappings = new HashMap<>();
	while (target != null) {
		// 查找所有的Mapping
		contextMappings.put(target.getId(), mappingsForContext(target));
		target = target.getParent();
	}
	return new ApplicationMappings(contextMappings);// 返回的信息就会json格式化到响应
}

// org.springframework.boot.actuate.web.mappings.MappingsEndpoint#mappingsForContext
private ContextMappings mappingsForContext(ApplicationContext applicationContext) {
	Map<String, Object> mappings = new HashMap<>();
	this.descriptionProviders.forEach(
			(provider) -> mappings.put(provider.getMappingName(), provider.describeMappings(applicationContext)));
	return new ContextMappings(mappings,
			(applicationContext.getParent() != null) ? applicationContext.getId() : null);
}

Springboot应用执行器Actuator源码分析_java_04

(3)执行结果

Springboot应用执行器Actuator源码分析_spring boot_05


Springboot应用执行器Actuator源码分析_Endpoint_06

4、ShutdownEndpoint自动装配原理

(1)自动装配类

@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = ShutdownEndpoint.class)
public class ShutdownEndpointAutoConfiguration {

	@Bean(destroyMethod = "")
	@ConditionalOnMissingBean
	public ShutdownEndpoint shutdownEndpoint() {
		return new ShutdownEndpoint();
	}

}

(2)ShutdownEndpoint

// 默认是不开启的,因为安全性要求极高
@Endpoint(id = "shutdown", enableByDefault = false)
public class ShutdownEndpoint implements ApplicationContextAware {

	private static final Map<String, String> NO_CONTEXT_MESSAGE = Collections
		.unmodifiableMap(Collections.singletonMap("message", "No context to shutdown."));

	private static final Map<String, String> SHUTDOWN_MESSAGE = Collections
		.unmodifiableMap(Collections.singletonMap("message", "Shutting down, bye..."));

	private ConfigurableApplicationContext context;

	// 写操作
	@WriteOperation
	public Map<String, String> shutdown() {
		if (this.context == null) {
			return NO_CONTEXT_MESSAGE; // 返回的信息就会json格式化到响应
		}
		try {
			return SHUTDOWN_MESSAGE;
		}
		finally {
			// 另起一个线程进行shutdown操作,目的是优雅关机。
			Thread thread = new Thread(this::performShutdown);
			thread.setContextClassLoader(getClass().getClassLoader());
			thread.start();
		}
	}

	private void performShutdown() {
		try {
			// 暂停500毫秒
			Thread.sleep(500L);
		}
		catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
		}
		// 执行Spring容器关闭操作
		this.context.close();
	}

	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		if (context instanceof ConfigurableApplicationContext) {
			this.context = (ConfigurableApplicationContext) context;
		}
	}

}