Springboot应用执行器Actuator源码分析

@[TOC]

一、认识Actuator

1、回顾Actuator

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

Spring Boot Actuator ------健康检查神器

2、Actuator重要端点

二、源码分析

1、Endpoint自动装配

(1)自动配置入口

(2)普通Endpoint自动装配

java 复制代码
@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进行自动装配。

java 复制代码
// 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映射。

java 复制代码
// 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)自动装配类

java 复制代码
@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = BeansEndpoint.class)
public class BeansEndpointAutoConfiguration {

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

}

(2)BeansEndpoint

java 复制代码
// id就是可以访问的web路径
@Endpoint(id = "beans")
public class BeansEndpoint {
java 复制代码
// 读操作
@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);
}
java 复制代码
// 返回的对象
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)执行结果

3、MappingsEndpoint自动装配原理

(1)自动装配类

java 复制代码
@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

java 复制代码
// web访问路径
@Endpoint(id = "mappings")
public class MappingsEndpoint {
java 复制代码
// 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);
}

(3)执行结果

4、ShutdownEndpoint自动装配原理

(1)自动装配类

java 复制代码
@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = ShutdownEndpoint.class)
public class ShutdownEndpointAutoConfiguration {

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

}

(2)ShutdownEndpoint

java 复制代码
// 默认是不开启的,因为安全性要求极高
@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;
		}
	}

}
相关推荐
AskHarries1 小时前
Java字节码增强库ByteBuddy
java·后端
佳佳_1 小时前
Spring Boot 应用启动时打印配置类信息
spring boot·后端
许野平2 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
BiteCode_咬一口代码3 小时前
信息泄露!默认密码的危害,记一次网络安全研究
后端
齐 飞4 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
LunarCod4 小时前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发
码农派大星。5 小时前
Spring Boot 配置文件
java·spring boot·后端
杜杜的man5 小时前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*5 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu6 小时前
Go语言结构体、方法与接口
开发语言·后端·golang