序
本文主要研究下springboot2的MappingsEndpoint
MappingsEndpointAutoConfiguration
spring-boot-actuator-autoconfigure-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfiguration.java
@ManagementContextConfigurationpublic class MappingsEndpointAutoConfiguration { @Bean @ConditionalOnEnabledEndpoint public MappingsEndpoint mappingsEndpoint(ApplicationContext applicationContext, ObjectProvider> descriptionProviders) { return new MappingsEndpoint( descriptionProviders.getIfAvailable(Collections::emptyList), applicationContext); } @Configuration @ConditionalOnWebApplication(type = Type.SERVLET) static class ServletWebConfiguration { @Bean ServletsMappingDescriptionProvider servletMappingDescriptionProvider() { return new ServletsMappingDescriptionProvider(); } @Bean FiltersMappingDescriptionProvider filterMappingDescriptionProvider() { return new FiltersMappingDescriptionProvider(); } @Configuration @ConditionalOnClass(DispatcherServlet.class) @ConditionalOnBean(DispatcherServlet.class) static class SpringMvcConfiguration { @Bean DispatcherServletsMappingDescriptionProvider dispatcherServletMappingDescriptionProvider() { return new DispatcherServletsMappingDescriptionProvider(); } } } @Configuration @ConditionalOnWebApplication(type = Type.REACTIVE) @ConditionalOnClass(DispatcherHandler.class) @ConditionalOnBean(DispatcherHandler.class) static class ReactiveWebConfiguration { @Bean public DispatcherHandlersMappingDescriptionProvider dispatcherHandlerMappingDescriptionProvider( ApplicationContext applicationContext) { return new DispatcherHandlersMappingDescriptionProvider(); } }}复制代码
这里使用descriptionProviders创建mappingsEndpoint,然后根据是servlet或reactive的方式来创建不同的MappingDescriptionProvider,servlet创建的是ServletsMappingDescriptionProvider,FiltersMappingDescriptionProvider,DispatcherServletsMappingDescriptionProvider,reactive创建的是DispatcherHandlersMappingDescriptionProvider
MappingsEndpoint
spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/web/mappings/MappingsEndpoint.java
@Endpoint(id = "mappings")public class MappingsEndpoint { private final CollectiondescriptionProviders; private final ApplicationContext context; public MappingsEndpoint(Collection descriptionProviders, ApplicationContext context) { this.descriptionProviders = descriptionProviders; this.context = context; } @ReadOperation public ApplicationMappings mappings() { ApplicationContext target = this.context; Map contextMappings = new HashMap<>(); while (target != null) { contextMappings.put(target.getId(), mappingsForContext(target)); target = target.getParent(); } return new ApplicationMappings(contextMappings); } private ContextMappings mappingsForContext(ApplicationContext applicationContext) { Map mappings = new HashMap<>(); this.descriptionProviders .forEach((provider) -> mappings.put(provider.getMappingName(), provider.describeMappings(applicationContext))); return new ContextMappings(mappings, applicationContext.getParent() == null ? null : applicationContext.getId()); } //......}复制代码
这里根据descriptionProviders创建ContextMappings
servlet方式
ServletsMappingDescriptionProvider
spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/web/mappings/servlet/ServletsMappingDescriptionProvider.java
public class ServletsMappingDescriptionProvider implements MappingDescriptionProvider { @Override public ListdescribeMappings( ApplicationContext context) { if (!(context instanceof WebApplicationContext)) { return Collections.emptyList(); } return ((WebApplicationContext) context).getServletContext() .getServletRegistrations().values().stream() .map(ServletRegistrationMappingDescription::new) .collect(Collectors.toList()); } @Override public String getMappingName() { return "servlets"; }}复制代码
这里从servletContext中获取ServletRegistrations,再获取ServletRegistrationMappingDescription
FiltersMappingDescriptionProvider
spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/web/mappings/servlet/FiltersMappingDescriptionProvider.java
public class FiltersMappingDescriptionProvider implements MappingDescriptionProvider { @Override public ListdescribeMappings( ApplicationContext context) { if (!(context instanceof WebApplicationContext)) { return Collections.emptyList(); } return ((WebApplicationContext) context).getServletContext() .getFilterRegistrations().values().stream() .map(FilterRegistrationMappingDescription::new) .collect(Collectors.toList()); } @Override public String getMappingName() { return "servletFilters"; }}复制代码
这里从servletContext中获取FilterRegistrations,再获取FilterRegistrationMappingDescription
DispatcherServletsMappingDescriptionProvider
spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java
public class DispatcherServletsMappingDescriptionProvider implements MappingDescriptionProvider { private static final List> descriptionProviders; static { List > providers = new ArrayList<>(); providers.add(new RequestMappingInfoHandlerMappingDescriptionProvider()); providers.add(new UrlHandlerMappingDescriptionProvider()); if (ClassUtils.isPresent( "org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping", null)) { providers.add(new DelegatingHandlerMappingDescriptionProvider( new ArrayList<>(providers))); } descriptionProviders = Collections.unmodifiableList(providers); } @Override public String getMappingName() { return "dispatcherServlets"; } @Override public Map > describeMappings( ApplicationContext context) { if (context instanceof WebApplicationContext) { return describeMappings((WebApplicationContext) context); } return Collections.emptyMap(); } private Map > describeMappings( WebApplicationContext context) { Map > mappings = new HashMap<>(); context.getBeansOfType(DispatcherServlet.class) .forEach((name, dispatcherServlet) -> mappings.put(name, describeMappings(new DispatcherServletHandlerMappings(name, dispatcherServlet, context)))); return mappings; } private List describeMappings( DispatcherServletHandlerMappings mappings) { return mappings.getHandlerMappings().stream().flatMap(this::describe) .collect(Collectors.toList()); } private Stream describe( T handlerMapping) { return describe(handlerMapping, descriptionProviders).stream(); } @SuppressWarnings("unchecked") private static List describe( T handlerMapping, List > descriptionProviders) { for (HandlerMappingDescriptionProvider descriptionProvider : descriptionProviders) { if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) { return ((HandlerMappingDescriptionProvider ) descriptionProvider) .describe(handlerMapping); } } return Collections.emptyList(); } //......}复制代码
这里主要从DelegatingHandlerMappingDescriptionProvider、RequestMappingInfoHandlerMappingDescriptionProvider、UrlHandlerMappingDescriptionProvider获取DispatcherServletMappingDescription
reactive方式
DispatcherHandlersMappingDescriptionProvider
spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/web/mappings/reactive/DispatcherHandlersMappingDescriptionProvider.java
public class DispatcherHandlersMappingDescriptionProvider implements MappingDescriptionProvider { private static final List> descriptionProviders = Arrays .asList(new RequestMappingInfoHandlerMappingDescriptionProvider(), new UrlHandlerMappingDescriptionProvider(), new RouterFunctionMappingDescriptionProvider()); @Override public String getMappingName() { return "dispatcherHandlers"; } @Override public Map > describeMappings( ApplicationContext context) { Map > mappings = new HashMap<>(); context.getBeansOfType(DispatcherHandler.class).forEach( (name, handler) -> mappings.put(name, describeMappings(handler))); return mappings; } private List describeMappings( DispatcherHandler dispatcherHandler) { return dispatcherHandler.getHandlerMappings().stream().flatMap(this::describe) .collect(Collectors.toList()); } @SuppressWarnings("unchecked") private Stream describe( T handlerMapping) { for (HandlerMappingDescriptionProvider descriptionProvider : descriptionProviders) { if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) { return ((HandlerMappingDescriptionProvider ) descriptionProvider) .describe(handlerMapping).stream(); } } return Stream.empty(); } //......}复制代码
与servlet获取DispatcherServletsMappingDescriptionProvider不同,reactive获取的是DispatcherHandlersMappingDescriptionProvider 主要从RequestMappingInfoHandlerMappingDescriptionProvider、RouterFunctionMappingDescriptionProvider、UrlHandlerMappingDescriptionProvider这三个来获取HandlerMappingDescriptionProvider
小结
springboot2的MappingsEndpoint通过provider根据servlet及reactive分别进行各自的mappings获取,servlet主要分为ServletsMappingDescriptionProvider、FiltersMappingDescriptionProvider、DispatcherServletsMappingDescriptionProvider,而reactive主要分为DispatcherHandlersMappingDescriptionProvider