spring boot 源码解析56-actuator请求处理流程(以EnvironmentEndpoint为例)

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

前言

前面2篇文章介绍了EndpointHandlerMapping.本文就来看一下访问MvcEndpoint的处理流程.

本文以访问/env 为例进行讲解

解析

  1. 因为我们是get请求,因此为调用FrameworkServlet#doGet来进行处理,代码如下:

        protected final void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            processRequest(request, response);
        }

    在该方法中最终调用了DispatcherServlet#doService,而在该方法中最终调用了doDispatch方法

  2. 在该方法中首先调用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个,如下:

    1. SimpleUrlHandlerMapping
    2. EndpointHandlerMapping
    3. RequestMappingHandlerMapping
    4. BeanNameUrlHandlerMapping
    5. SimpleUrlHandlerMapping
    6. EmptyHandlerMapping
    7. EmptyHandlerMapping
    8. WelcomePageHandlerMapping

    此时最终调用的是EndpointHandlerMapping#getHandler 获得对应的HandlerExecutionChain.代码如下:

        List 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 interceptors = new ArrayList();
            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

  3. 接下来调用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:

    1. RequestMappingHandlerAdapter
    2. HttpRequestHandlerAdapter
    3. SimpleControllerHandlerAdapter

    最终返回的是RequestMappingHandlerAdapter.代码如下:

        public final boolean supports(Object handler) {
            return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
        }

    其supportsInternal 返回true.代码如下:

        protected boolean supportsInternal(HandlerMethod handlerMethod) {
            return true;
        }
  4. 接下来执行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.其实现分别如下:

    1. SkipPathExtensionContentNegotiation,代码如下:

          public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                  Object handler) throws Exception {
              request.setAttribute(SKIP_ATTRIBUTE, Boolean.TRUE);
              return true;
          }
    2. 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全网独家揭秘

  5. 接下来调用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() // 最终执行到
  6. 后续的渲染,就不必要贴出了,因为最重要的调用逻辑已经讲明了.后面的处理都是通用的,读者可以自行阅读.

来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring boot 源码解析56-actuator请求处理流程(以EnvironmentEndpoint为例)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏