需要先明确一个很重要的点:actuator支持多种框架,包括JMX、WebFlux(响应式web应用)、SpringMVC(基于servlet)、Servlet等,在不同的环境中,使用不同的配置。
Ps:关于JMX,它能够让我们管理、监视和配置应用。是可在线更改配置的那种,包括正在使用的配置bean。只要注册到了MBeanServer。所以用它来对外提供暴露端点,也是个不错的选择。
在了解Endpoint的创建和注册之前,需要先了解以下知识点。
EndpointsSupplier也就是Endpoint提供者,负责向ServletEndpointRegistrar暴露端点(在registrar创建时会调用get, 会发现并创建Endpoint),它具有端点过滤能力(ExposeExcludePropertyEndpointFilter)。
在SpringMVC工程下,将会在WebEndpointAutoConfiguration配置类中配置一个
WebEndpointDiscoverer作为supplier
类图:
ServletEndpointSupplier 负责@ServletEndpoint有以下四大类:
WebEndpointsSupplier 负责@WebEndpoint
JmxEndpointsSupplier 负责@JmxEndpoint
ControllerEndpointsSupplier 负责@ControllerEndpoint & @RestControllerEndpoint
其对应的实现类,相信从类图中不难看出。
处理器映射器HandlerMapping,这个概念应该比较熟悉了,就是SpringMVC的概念,负责路径映射到具体的控制器的。
Endpoint的主要注解有:
@Endpoint 官方推荐使用,不绑定特定技术(支持JMX, SpringMVC, Spring WebFlux, Jersey etc.)
@WebEndpoint 基于WEB技术
@ControllerEndpoint @RestControllerEndpoint 基于Controller
@ServletEndpoint 基于Servlet
@EndpointExtension 将Endpoint拓展到特定技术下使用,通常不直接使用该注解,而使用它的组合注解,例如:@EndpointWebExtension拓展到Web技术下(例:SpringMVC Spring WebFlux) @EndpointJmxExtension
Endpoint的封装
在访问Endpoint的时候,我们直接访问的并不是被@Endpoint注解的类,而是被经过封装的能被特定的技术下使用的类,情况与Supplier一一对应。(实际上先封装成EndpointBean然后再封装成下面的对应的Endpoint类型)
DiscoveredJmxEndpoint ServletEndpointSupplier与Supplier对应关系如下:
DiscoveredServletEndpoint ServletEndpointSupplier
DiscoveredWebEndpoint WebEndpointsSupplier
DiscoveredControllerEndpoint ControllerEndpointsSupplier
在类图中,应该注意到PathMappedEndpoint接口,在Web技术下,所有实现该接口的Endpoint类型都支持通过HTTP请求访问。而四大Endpoint也都实现了AbstractDiscoveredEndpoint,所以也是可以被暴露到外部实现真正访问的(前提是在配置中include)。
那么,Endpoint是何时被发现和封装的呢?
在配置WebEndpointAutoConfiguration#pathMappedEndpoints,注入PathMappedEndpoints时,会通过supplier获取所有PathMappedEndpoint类型的Endpoint,如果为空,则会进入Endpoint的发现与封装。这时就会把所有暴露的Endpoint封装成DiscoveredWebEndpoint (SpringMVC) 并且被PathMappedEndpoints所管理。PathMappedEndpoints有一个通过EndpointID来获取Endpoint的方法。到这里,相信聪明的你应该反映过来为什么请求路径就是@Endpoint注解时的id了吧。
在创建Endpoint时,会调用超类EndpointDiscoverer.converToEndpoint方法,他会根据@Endpoint中的@XXXOperation织入一个DiscoveredWebOperation(在注册Endpoint时,也会再次封装成RequestMappingInfo)。
那么DiscoveredWebOperation又是个啥?先上个类图
类图中,只有两类Operation,DiscoveredWebOperation见名思意,自然是负责HTTP发布的Endpoint,DiscoveredJmxOperation负责JMX发布的Endpoint。看超类AbstractDiscoveredOperation属性,这个invoker可是负责完成调用operation操作的。而operationMethod就是对应Endpoint带@XXXOperation注解的方法。由下面代码截图第二张中可以看出invoker是ReflectiveOperationInvoker通过反射调用的。operationMethod是DiscoveredOperationMethod。
DiscoveredOperationsFactory#createOperations(String id, Object target):71先来看看DiscoveredWebOperation是怎么创建的?
DiscoveredOperationsFactory#createOperation(String,Object, Method, OperationType, Class):77 ->
DiscoveredOperationsFactory#createOperation(String, Object, Method, OperationType, Class):84 ->
DiscoveredOperationsFactory#createOperation(String, DiscoveredOperationMethod, OperationInvoker)
Operation注意了,这里两种Operation都在这里创建的,具体创建的是哪一种,主要看EndpointDiscover.this是谁,如果是WebEndpointDiscoverer,创建的就是DiscoveredWebOperation。最后再将该Operation一起封装到Endpoint
但是这些端点虽然都持有了operation,又是在哪里注册的呢?怎么织入SpringMVC的呢?由此需要引出WebMvcEndpointHandlerMapping,在WebMvcEndpointManagementContextConfiguration#webEndpointServletHandlerMapping配置,当然,需要在各种supplier都加载完成各自的工作,例如发现封装Endpoint,之后。创建该类时,超类AbstractWebMvcEndpointHandlerMapping会执行initHandlerMethods进行初始化。他会调用registerMappingForOperation对Endpoint进行注册。
将operation再次封装成RequestMappingInfo,并创建一个handler再注册。如果对SpringMVC的请求映射信息RequestMappingInfo感兴趣的同学可以读一读:RequestMappingInfo相关文章
registerMapping方法其实是超类AbstractHandlerMethodMapping的方法,该超类其实是SpringMVC的范畴。SpringMVC注册控制器也是通过这个方法。只不过是在初始化方法AbstractHandlerMethodMapping#initHandlerMethods中,通过detectHandlerMethods的下面这段代码。(对SpringMVC注册Controller感兴趣的同学:献上文章)
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
这两个方法都只有一句且一毛一样的代码:
this.mappingRegistry.register(mapping, handler, method);
回过头,从SpringMVC的角度,看Endpoint请求。
HealthEndpoint在SpringMVC下,起作用的是HealthEndpointWebExtension哈。有兴趣的同学可以在上述步骤断点试试。自定义Endpoint时,直接使用@Endpoint注解不需要再写个@EndpointWebExtension,也是同样起作用的。
文章稍微有点乱,各位看官别介哈,已经是懒癌晚期。。。。
温馨提示:工程中使用的是SpringMVC,所以与WebEndpoint相关的配置都会起作用。
@Endpoint会自动选择这部分的配置来构建。
技能get:在看Spring源码的时候,一定要明确当前工程使用的技术.众所周知,Spring以良好的拓展性著称。
所以SpringBoot在构建默认的自动配置时,自然会考虑到这些技术的兼容配置。所以在看源码的时候一定要注意
当前系统所使用的技术,不然多走很多弯路。重点关注当前工程下的技术实现即可。