前言
前面2篇文章介绍了EndpointHandlerMapping.本文就来看一下访问MvcEndpoint的处理流程.
本文以访问/env 为例进行讲解
解析
因为我们是get请求,因此为调用FrameworkServlet#doGet来进行处理,代码如下:
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
在该方法中最终调用了DispatcherServlet#doService,而在该方法中最终调用了doDispatch方法
在该方法中首先调用getHandler方法,获得HandlerExecutionChain.代码如下:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
遍历其持有的HandlerMappings,依次调用其getHandler获得HandlerExecutionChain,如果获得对应的HandlerExecutionChain,则直接返回.如果没有匹配的HandlerExecutionChain的话,则返回null.
此时, DispatcherServlet 持有的HandlerMapping有8个,如下:
- SimpleUrlHandlerMapping
- EndpointHandlerMapping
- RequestMappingHandlerMapping
- BeanNameUrlHandlerMapping
- SimpleUrlHandlerMapping
- EmptyHandlerMapping
- EmptyHandlerMapping
- WelcomePageHandlerMapping
此时最终调用的是EndpointHandlerMapping#getHandler 获得对应的HandlerExecutionChain.代码如下:
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
接下来调用AbstractHandlerMapping#getHandlerExecutionChain–> 添加Interceptor.
此时在EndpointHandlerMapping中持有的adaptedInterceptors只有1个SkipPathExtensionContentNegotiation 由于不是MappedInterceptor的实例,因此直接加到HandlerExecutionChain中.代码如下:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
由于securityInterceptor不等于null并且不是跨域请求,因此在原先的Interceptor基础上加上securityInterceptor.代码如下:
private HandlerExecutionChain addSecurityInterceptor(HandlerExecutionChain chain) { List<HandlerInterceptor> interceptors = new ArrayList<HandlerInterceptor>(); if (chain.getInterceptors() != null) { interceptors.addAll(Arrays.asList(chain.getInterceptors())); } interceptors.add(this.securityInterceptor); return new HandlerExecutionChain(chain.getHandler(), interceptors.toArray(new HandlerInterceptor[interceptors.size()])); }
因此此时Interceptor有2两个–>SkipPathExtensionContentNegotiation,securityInterceptor
接下来调用DispatcherServlet#getHandlerAdapter获得对应的HandlerAdapter.代码如下:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
此时有3个HandlerAdapter:
- RequestMappingHandlerAdapter
- HttpRequestHandlerAdapter
- SimpleControllerHandlerAdapter
最终返回的是RequestMappingHandlerAdapter.代码如下:
public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
其supportsInternal 返回true.代码如下:
protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; }
接下来执行HandlerExecutionChain#applyPreHandle方法,依次调用其持有的Interceptor的preHandle方法,代码如下:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
此时持有的是SkipPathExtensionContentNegotiation,MvcEndpointSecurityInterceptor.其实现分别如下:
SkipPathExtensionContentNegotiation,代码如下:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.setAttribute(SKIP_ATTRIBUTE, Boolean.TRUE); return true; }
MvcEndpointSecurityInterceptor,代码如下:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1. 如果是(cors请求并且是options类型的请求并且请求头Access-Control-Request-Method存在)或者(不进行校验),则直接返回true if (CorsUtils.isPreFlightRequest(request) || !this.secure) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; // 2. 如果是options请求并且HandlerMethod不是MvcEndpoint的实例,则返回true if (HttpMethod.OPTIONS.matches(request.getMethod()) && !(handlerMethod.getBean() instanceof MvcEndpoint)) { return true; } MvcEndpoint mvcEndpoint = (MvcEndpoint) handlerMethod.getBean(); // 3. 如果配置的endpoints.sensitive=false或者对应的endpoints.xxx.sensitive=false,则直接返回true if (!mvcEndpoint.isSensitive()) { return true; } // 4. 如果拥有相应的权限则返回true if (isUserAllowedAccess(request)) { return true; } // 5. 返回401 sendFailureResponse(request, response); return false; }
关于这部分的内容,可以看spring boot 源码解析55-spring boot actuator HandlerMapping全网独家揭秘
接下来调用HandlerAdapter#handle,最终调用了EnvironmentEndpoint#invoke方法.这部分的调用链如下:
--> org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(HttpServletRequest, HttpServletResponse, Object) --> org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod) --> org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod) --> org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object...) --> org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(NativeWebRequest, ModelAndViewContainer, Object...) --> org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(Object...) --> org.springframework.boot.actuate.endpoint.EnvironmentEndpoint.invoke() // 最终执行到
后续的渲染,就不必要贴出了,因为最重要的调用逻辑已经讲明了.后面的处理都是通用的,读者可以自行阅读.