Spring Boot 2.1.3自定义Actuator端点参数必填问题求助
问题描述
创建了一个自定义Actuator端点,初始代码如下:
@Component @Endpoint(id="custom") public class CustomActuatorEndpoint { @ReadOperation public Map<String, List<String>> invoke3params(String param1, String param2, String param3) { return new HashMap<>(); } }
- 携带完整参数请求
/custom?param1=foo1¶m2=foo2¶m3=foo3时响应正常 - 仅传递部分参数(如
/custom?param1=foo1)或无参数请求时,返回HTTP 500,提示缺少必填参数
尝试过的方案及遇到的问题:
- 将参数改为
Optional<String>类型,仍返回HTTP 500,报错信息一致 - 定义多个重载的
@ReadOperation方法,应用启动失败并抛出异常:
2022-09-14T20:17:28.847Z ERROR --- [main] o.s.b.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pathMappedEndpoints' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints]: Factory method 'pathMappedEndpoints' threw exception; nested exception is java.lang.IllegalStateException: Unable to map duplicate endpoint operations: [web request predicate GET to path 'custom' produces: application/vnd.spring-boot.actuate.v2+json,application/json]
解决方案
方法1:使用@Nullable标记可选参数
Spring Boot Actuator的端点参数默认是必填项,需显式使用org.springframework.lang.Nullable注解标记参数为可选,这样即使参数未传递,也不会触发必填校验:
import org.springframework.lang.Nullable; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.List; @Component @Endpoint(id="custom") public class CustomActuatorEndpoint { @ReadOperation public Map<String, List<String>> invoke3params(@Nullable String param1, @Nullable String param2, @Nullable String param3) { Map<String, List<String>> result = new HashMap<>(); if (param1 != null) { result.put("param1", Collections.singletonList(param1)); } if (param2 != null) { result.put("param2", Collections.singletonList(param2)); } if (param3 != null) { result.put("param3", Collections.singletonList(param3)); } return result; } }
方法2:为参数设置默认值
如果希望参数未传递时使用默认值,可直接在方法参数上指定默认值:
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.List; @Component @Endpoint(id="custom") public class CustomActuatorEndpoint { @ReadOperation public Map<String, List<String>> invoke3params(String param1 = "default1", String param2 = "default2", String param3 = "default3") { Map<String, List<String>> result = new HashMap<>(); result.put("param1", Collections.singletonList(param1)); result.put("param2", Collections.singletonList(param2)); result.put("param3", Collections.singletonList(param3)); return result; } }
无效方案原因说明
Optional类型不生效:Spring Boot Actuator的端点参数解析逻辑未对Optional类型做特殊处理,仍将其视为必填参数,因此需用@Nullable显式声明可选性。- 重载
@ReadOperation方法失败:Actuator不允许同一个端点下存在多个相同HTTP方法的操作(此处均为GET请求),因为无法区分映射规则,所以会触发重复映射的异常。
内容的提问来源于stack exchange,提问作者Battle_Slug

