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;
		}
	}

}
相关推荐
红尘散仙3 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记4 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆4 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪5 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6165 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364575 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao6 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
IT_陈寒7 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
ayqy贾杰8 小时前
基层管理的三板斧,在AI时代行不通了
前端·后端·团队管理
Apifox8 小时前
Apifox 5 月更新|Postman 导入优化、Runner 支持非 root 运行、请求代码自动带鉴权
前端·后端·安全