如何在Spring Boot中默认启用自定义Actuator端点?
我开发了一个小型库,可为Actuator添加自定义端点jwks,希望默认暴露该端点。Spring Boot 2.7.4默认仅暴露health端点。目前我通过注册EnvironmentPostProcessor来修改management.endpoints.web.exposure.include属性,但这种操作PropertySource的方式略显脆弱。另外还有其他库需要默认暴露各自的端点(如metrics、prometheus等),当前实现代码如下:
public class PoCEnvironmentPostProcessor implements EnvironmentPostProcessor { private static final String PROPERTY_NAME = "management.endpoints.web.exposure.include"; @Override public void postProcessEnvironment( ConfigurableEnvironment environment, SpringApplication application ) { var propertySources = environment.getPropertySources(); propertySources.stream() .filter(it -> it.containsProperty(PROPERTY_NAME)) .findFirst().ifPresentOrElse(source -> { var property = source.getProperty(PROPERTY_NAME); var pocSource = new MapPropertySource(PROPERTY_NAME, Map.of(PROPERTY_NAME, property + ",jwks")); // Add the new property with more priority propertySources.addBefore(source.getName(), pocSource); }, () -> { var pocSource = new MapPropertySource(PROPERTY_NAME, Map.of(PROPERTY_NAME, "health,jwks")); propertySources.addLast(pocSource); }); } }
请问是否存在无需过多操作PropertySource,即可默认暴露端点并支持多库添加不同端点的方法?
解决方案
方法1:通过EndpointWebExtension控制端点暴露(推荐)
Spring Boot Actuator提供了端点扩展机制,每个库可以独立控制自身端点的默认暴露状态,无需修改全局配置属性。为自定义端点实现EndpointWebExtension并重写isExposed()方法:
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; @Endpoint(id = "jwks") public class JwksEndpoint { @ReadOperation public String getJwks() { // 端点业务逻辑 return "jwks content"; } } @EndpointWebExtension(endpoint = JwksEndpoint.class) public class JwksEndpointWebExtension { private final JwksEndpoint delegate; public JwksEndpointWebExtension(JwksEndpoint delegate) { this.delegate = delegate; } @ReadOperation public WebEndpointResponse<String> getJwks() { return new WebEndpointResponse<>(delegate.getJwks(), 200); } // 核心:设置该端点默认通过Web暴露 @Override public boolean isExposed() { return true; } }
这种方式完全隔离了不同库的端点配置,不会出现属性覆盖或冲突问题。
方法2:自动配置中直接修改WebEndpointProperties
利用Spring Boot的自动配置和属性绑定机制,直接操作Actuator的端点配置属性,比手动修改PropertySource更安全可靠:
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(WebEndpointProperties.class) public class JwksEndpointAutoConfiguration { public JwksEndpointAutoConfiguration(WebEndpointProperties webEndpointProperties) { // 将jwks添加到默认暴露列表,Spring会自动处理属性合并(用户配置优先级更高) var includeList = webEndpointProperties.getExposure().getInclude(); if (!includeList.contains("jwks")) { includeList.add("jwks"); } } @Bean @ConditionalOnMissingBean public JwksEndpoint jwksEndpoint() { return new JwksEndpoint(); } }
多个库可以通过各自的自动配置类向includeList中添加端点,Spring会自动完成列表合并,不会互相覆盖。
方法3:自定义配置属性增强灵活性
如果需要允许用户关闭端点的默认暴露,可以自定义配置属性,再在自动配置中根据属性值决定是否添加端点:
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties({JwksEndpointProperties.class, WebEndpointProperties.class}) public class JwksAutoConfiguration { public JwksAutoConfiguration(JwksEndpointProperties jwksProps, WebEndpointProperties webEndpointProps) { // 根据自定义属性决定是否默认暴露 if (jwksProps.isExposeByDefault()) { var includeList = webEndpointProps.getExposure().getInclude(); if (!includeList.contains("jwks")) { includeList.add("jwks"); } } } } @ConfigurationProperties(prefix = "management.endpoint.jwks") public class JwksEndpointProperties { // 默认开启暴露 private boolean exposeByDefault = true; // getter、setter public boolean isExposeByDefault() { return exposeByDefault; } public void setExposeByDefault(boolean exposeByDefault) { this.exposeByDefault = exposeByDefault; } }
用户可通过management.endpoint.jwks.expose-by-default=false手动关闭该端点的默认暴露,兼顾默认行为和灵活性。
内容的提问来源于stack exchange,提问作者Víctor Herraiz

