在过滤器中识别对 Spring Boot Actuator 端点的请求
Identify request to a Spring Boot Actuator endpoint in Filter
如何识别请求是针对 javax.servlet.Filter
中的任何 Spring 个引导执行器端点?
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// Is req to any of Spring Actuator endpoint?
chain.doFilter(req, res);
}
我的想法是搜索调用程序 class 或程序包 (org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter),但我不知道具体如何。
这是启动时应用程序日志的一部分。
EndpointHandlerMapping : Mapped "{[/env/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
EndpointHandlerMapping : Mapped "{[/env || /env.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/trace || /trace.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/archaius || /archaius.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/configprops || /configprops.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/health || /health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)
EndpointHandlerMapping : Mapped "{[/features || /features.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/prometheus || /prometheus.json],methods=[GET]}" onto public java.lang.Object io.micrometer.spring.autoconfigure.export.prometheus.PrometheusScrapeMvcEndpoint.invoke()
EndpointHandlerMapping : Mapped "{[/loggers || /loggers.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/info || /info.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/dump || /dump.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/env],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.context.environment.EnvironmentManagerMvcEndpoint.value(java.util.Map<java.lang.String, java.lang.String>)
EndpointHandlerMapping : Mapped "{[/mappings || /mappings.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/refresh || /refresh.json],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.endpoint.GenericPostableMvcEndpoint.invoke()
您可以将执行器上下文路径更改为 /management,以便所有请求都到达 http://<host>:<port>/management/<here-come-your-endpoints>
在我们使用的Spring Boot 1.5.3中可以通过指定属性轻松完成:
management.context-path=/management
在application.properties文件中
这使得执行器易于跟踪,并允许在网关公开什么和不公开什么时进行灵活配置。
Spring 引导 2:
看来Spring Boot 2
的情况每个子版本都不一样。以下代码主要是为了灵感,必须针对特定的 Spring 引导版本进行裁剪:
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
public class ActuatorEndpointFilter implements javax.servlet.Filter {
@Inject
private WebMvcEndpointHandlerMapping mvcepMapping;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HandlerExecutionChain handlerChain = mvcepMapping.getHandler((HttpServletRequest) request);
if (handlerChain != null) {
Object handler = handlerChain.getHandler();
// Following condition is enought in Spring Boot 2.1.1 and 2.1.2.
if (handler.getClass().getName().startsWith(
"org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping")) {
// IT IS ACTUATOR ENDPOINT in Spring 2.1.1 and 2.1.2!!!!
}
// Following conditions are mandatory in Spring Boot <= 2.1.0.RELEASE
if (handler instanceof HandlerMethod) {
Object bean = ((HandlerMethod) handler).getBean();
if (bean.getClass().getName().startsWith(
"org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping")) {
// IT IS ACTUATOR ENDPOINT in Spring 2.1.0!!!!
}
}
}
}
chain.doFilter(request, response);
}
}
我怀疑第一个条件,if (handlerChain != null)
即:如果 WebMvcEndpointHandlerMapping
returns 一个处理程序,目前对于任何 Spring Boot 2版本,不过我没有深究。
如何识别请求是针对 javax.servlet.Filter
中的任何 Spring 个引导执行器端点?
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// Is req to any of Spring Actuator endpoint?
chain.doFilter(req, res);
}
我的想法是搜索调用程序 class 或程序包 (org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter),但我不知道具体如何。
这是启动时应用程序日志的一部分。
EndpointHandlerMapping : Mapped "{[/env/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
EndpointHandlerMapping : Mapped "{[/env || /env.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/trace || /trace.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/archaius || /archaius.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/configprops || /configprops.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/health || /health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)
EndpointHandlerMapping : Mapped "{[/features || /features.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/prometheus || /prometheus.json],methods=[GET]}" onto public java.lang.Object io.micrometer.spring.autoconfigure.export.prometheus.PrometheusScrapeMvcEndpoint.invoke()
EndpointHandlerMapping : Mapped "{[/loggers || /loggers.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/info || /info.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/dump || /dump.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/env],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.context.environment.EnvironmentManagerMvcEndpoint.value(java.util.Map<java.lang.String, java.lang.String>)
EndpointHandlerMapping : Mapped "{[/mappings || /mappings.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
EndpointHandlerMapping : Mapped "{[/refresh || /refresh.json],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.endpoint.GenericPostableMvcEndpoint.invoke()
您可以将执行器上下文路径更改为 /management,以便所有请求都到达 http://<host>:<port>/management/<here-come-your-endpoints>
在我们使用的Spring Boot 1.5.3中可以通过指定属性轻松完成:
management.context-path=/management
在application.properties文件中
这使得执行器易于跟踪,并允许在网关公开什么和不公开什么时进行灵活配置。
Spring 引导 2:
看来Spring Boot 2
的情况每个子版本都不一样。以下代码主要是为了灵感,必须针对特定的 Spring 引导版本进行裁剪:
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
public class ActuatorEndpointFilter implements javax.servlet.Filter {
@Inject
private WebMvcEndpointHandlerMapping mvcepMapping;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HandlerExecutionChain handlerChain = mvcepMapping.getHandler((HttpServletRequest) request);
if (handlerChain != null) {
Object handler = handlerChain.getHandler();
// Following condition is enought in Spring Boot 2.1.1 and 2.1.2.
if (handler.getClass().getName().startsWith(
"org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping")) {
// IT IS ACTUATOR ENDPOINT in Spring 2.1.1 and 2.1.2!!!!
}
// Following conditions are mandatory in Spring Boot <= 2.1.0.RELEASE
if (handler instanceof HandlerMethod) {
Object bean = ((HandlerMethod) handler).getBean();
if (bean.getClass().getName().startsWith(
"org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping")) {
// IT IS ACTUATOR ENDPOINT in Spring 2.1.0!!!!
}
}
}
}
chain.doFilter(request, response);
}
}
我怀疑第一个条件,if (handlerChain != null)
即:如果 WebMvcEndpointHandlerMapping
returns 一个处理程序,目前对于任何 Spring Boot 2版本,不过我没有深究。