美文网首页
spring源码------一个请求在spring中的处理过程(

spring源码------一个请求在spring中的处理过程(

作者: szhlcy | 来源:发表于2020-05-20 16:33 被阅读0次

    @[toc]

    前提

     这部分的内容是基于spring源码------一个请求在spring中的处理过程(从FrameworkServlet规范到DispatcherServlet)代码及流程图说明 (2)文章的进一步的对doDispatch方法的内部分析的。前面已经讲了getHandler方法的分析,这里就接着讲下一步的getHandlerAdapter方法

        protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ......
        //获取封装了HandlerInterceptor的HandlerExecutionChain
                    mappedHandler = getHandler(processedRequest);
                    //如果不存在对应的处理链则返回
                    if (mappedHandler == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
                    //从HandlerExecutionChain中获取Handler然后寻找合适的HandlerAdapter
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        ......
    }
    

    1.HandlerAdapter对象

     先根据官方的类注释来了解一下HandlerAdapter类的作用。这个类的作用是spring中的一个可扩展的接口类,允许对spring的允许对核心MVC工作流进行参数化,在DispatcherServlet中会对所有的这个类的实现类进行遍历,对于想要指定自己的web的工作流的开发者来说,可以实现这个接口。需要注意的是,实现这个接口的类,一般还需要实现Ordered接口或者贴上@Order注解来指定优先级。接下来对这个类的方法进行分析:

    public interface HandlerAdapter {
        
        boolean supports(Object handler);
        
        @Nullable
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
        
        long getLastModified(HttpServletRequest request, Object handler);
    }
    

     这几个方法的作用说明:

    1. supports
       这个方法作用就是在寻找合适的HandlerAdapter的时候,根据这个方法的返回结果来表示当前的HandlerAdapter是否适合处理当前的请求
    2. handle
       这个方法就是处理请求的方法,返回一个ModelAndView视图对象
    3. getLastModified
       这个是为了支持一些HandlerAdapter类不支持HttpServletgetLastModified方法用的。这个方法前面介绍过你们可以看看前面的文章。

    2. 获取HandlerAdapter对象的getHandlerAdapter方法

    2.1 getHandlerAdapter方法分析

     直接先看getHandlerAdapter方法的逻辑:

        protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            //寻找合适的HandlerAdapter
            if (this.handlerAdapters != null) {
                for (HandlerAdapter adapter : this.handlerAdapters) {
                    //如果找到了合适的就结束这个方法,直接返回
                    if (adapter.supports(handler)) {
                        return adapter;
                    }
                }
            }
            throw new ServletException("No adapter for handler [" + handler +
                    "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
        }
    

     可以看到逻辑很简单,就是遍历封装了HandlerAdapter对象的handlerAdapters这个成员遍历,寻找合适的HandlerAdapter然后返回。这里需要注意的是,找到了第一个合适的HandlerAdapter方法就会结束,所以HandlerAdapter在handlerAdapters中的顺序很重要,这也是上面的HandlerAdapter类描述中建议实现Ordered接口或者贴上@Order注解。
     关于handlerAdapters这个变量,他的填充是在上下文刷新的后进行填充的跟,逻辑在DispatchServlet类的initHandlerAdapters方法中。

        private void initHandlerAdapters(ApplicationContext context) {
            this.handlerAdapters = null;
            //是否寻找所有的HandlerAdapter,默认为true
            if (this.detectAllHandlerAdapters) {
                //在ApplicationContext中查找所有handleradapter,包括祖先上下文
                Map<String, HandlerAdapter> matchingBeans =
                        BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
                //如果存在则进行排序
                if (!matchingBeans.isEmpty()) {
                    this.handlerAdapters = new ArrayList<>(matchingBeans.values());
                    // We keep HandlerAdapters in sorted order.
                    AnnotationAwareOrderComparator.sort(this.handlerAdapters);
                }
            }
            else {
                try {
                    //如果不寻找所有的,则只寻找名称为handlerAdapter,类型为HandlerAdapter的bean
                    HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
                    this.handlerAdapters = Collections.singletonList(ha);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Ignore, we'll add a default HandlerAdapter later.
                }
            }
            ////如果容器中没有,则用默认的,一般情况下不会到这一波,关于默认的配置会读取DispatcherServlet.properties配置文件中的配置
            if (this.handlerAdapters == null) {
                this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
                if (logger.isTraceEnabled()) {
                    logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                            "': using default strategies from DispatcherServlet.properties");
                }
            }
        }
    
    2.1.1 容器中的HandlerAdapter对象以及实现的选择

     在spring中HandlerAdapter的子实现类会注册到容器中的有以下几个,RequestMappingHandlerAdapter,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter。这些类都是在WebMvcConfigurationSupport中用@Bean注解注册到容器中的。

    public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
        @Bean
        public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
                ContentNegotiationManager mvcContentNegotiationManager,
                FormattingConversionService mvcConversionService, Validator mvcValidator) {
    
            RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
            }
    
            @Bean
        public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
            return new HttpRequestHandlerAdapter();
        }
    
            @Bean
        public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
            return new SimpleControllerHandlerAdapter();
        }
    
    }
    

     其中RequestMappingHandlerAdapter的父类AbstractHandlerMethodAdapter实现了Ordred接口,设置的优先级,高于HttpRequestHandlerAdapterSimpleControllerHandlerAdapter这两个类(没事试下Ordred接口,也没有贴@Order注解),所以遍历的顺序也是这个类最先。因此每次请求第一个调用的就是RequestMappingHandlerAdapter方法。后面的分析都用这个类进行分析。

    private int order = Ordered.LOWEST_PRECEDENCE;
    
    public void setOrder(int order) {
            this.order = order;
        }
    
    2.1.2 RequestMappingHandlerAdaptersupports的实现

    RequestMappingHandlerAdapter的父类抽象类AbstractHandlerMethodAdapter实现了HandlerAdapter接口supports方法。

        @Override
        public final boolean
        supports(Object handler) {
            //handler是HandlerMethod的类型的,并且满足子类实现的判断逻辑
            return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
        }
    

     看看由RequestMappingHandlerAdapter实现的supportsInternal方法

        @Override
        protected boolean supportsInternal(HandlerMethod handlerMethod) {
            return true;
        }
    

     发现返回的是一个固定的true,因为任何方法参数和返回值类型都将以被处理。

    3. HandlerAdapter对请求处理的hadler方法

    3.1 逻辑交给子类实现的hadler方法

     在选择完HandlerAdapter后,会先调用HandlerExecutionChain的拦截器的preHandle方法。然后就会调用HandlerAdapter对请求进行处理了。
     进入到AbstractHandlerMethodAdapterhandle方法,逻辑完全委托给了子类去实现handleInternal方法来处理。

        public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
    
            return handleInternal(request, response, (HandlerMethod) handler);
        }
    

     实现的逻辑在RequestMappingHandlerAdapterhandleInternal方法中。

    3.2 handleInternal逻辑

        protected ModelAndView handleInternal(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ModelAndView mav;
            //检查请求方法是不是支持的,以及如果设置了需要session但是却不存在session(意思是当前请求的时候已经存在session了)
            checkRequest(request);
            // Execute invokeHandlerMethod in synchronized block if required.
            //是否在session级别上执行同步操作,默认为false
            if (this.synchronizeOnSession) {
                //获取session,如果不存在session,不创建新的session
                HttpSession session = request.getSession(false);
                //如果session不为空则在session上加锁
                if (session != null) {
                    Object mutex = WebUtils.getSessionMutex(session);
                    synchronized (mutex) {
                        //调用处理方法
                        mav = invokeHandlerMethod(request, response, handlerMethod);
                    }
                }
                else {//不存在session则不加锁处理
                    // No HttpSession available -> no mutex necessary
                    mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
            else {
                //不需要session同步,则直接调用处理方法
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
            //如果返回头不包含缓存控制相关的信息(Cache-Control属性表示缓存控制(缓存指的缓存服务器)相关的,这个可以自行查询相关资料了解)
            if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
                //根据,handlerMethod构建一个SessionAttributesHandler对象(会把对应的SessionAttributes注解封装起来),并判断是否存在@SessionAttributes注解属性
                if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                    //生产Http头
                    applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
                }
                else {
                    //准备返回
                    prepareResponse(response);
                }
            }
    
            return mav;
        }
    

     上面的方法逻辑也算是比较简单的,可以分为三步。

    1. 调用处理方法之前的请求检查,检查是否是支持的请求方式,请求是否在同一个session中
    2. 调用请求的处理方法,返回视图对象ModelAndView
    3. 检查response对象是否有缓存控制相关的操作,没有则进行相关的处理
    3.2.1 调用处理方法的逻辑invokeHandlerMethod

     上面的核心的步骤就在invokeHandlerMethod方法中,这个方法中的逻辑分支比较多,基本上一行代码就是一个逻辑步骤。相当于是一个聚合,spring中的代码很多都是这样的。这里就每一个步骤做什么进行讲解,但是不会深入到每个步骤的内部逻辑:

        protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
            //创建ServletWebRequest
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            try {
                //获取处理类中的所有的贴有@InitBinder注解的方法,然后封装处理为一个WebDataBinderFactory对象
                WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
                //获取处理类中的所有的贴有@ModelAttribute注解的方法,然后封装处理为一个WebDataBinderFactory对象
                ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
                //根据handlerMethod创建ServletInvocableHandlerMethod对象
                ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
                //设置请求参数解析器,这个参数解析器可以自定义
                if (this.argumentResolvers != null) {
                    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
                }
                //设置返回参数处理器,这个也可以自定义
                if (this.returnValueHandlers != null) {
                    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
                }
                //设置前面处理的封装@InitBinder注解信息的WebDataBinderFactory
                invocableMethod.setDataBinderFactory(binderFactory);
                //设置方法跟构造器参数解析的类
                invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
                //创建视图容器
                ModelAndViewContainer mavContainer = new ModelAndViewContainer();
                //把上下文中的跟这个请求相关的请求放到返回时的视图中, 这里的相关的请求指的是请求包含或者请求转发
                mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
                //调用所有 贴有ModelAttribute注解的方法,将返回结果添加到视图中
                modelFactory.initModel(webRequest, mavContainer, invocableMethod);
                //设置是否忽略 重定向时候的默认模型
                mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
                //设置异步请求相关的
                AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
                asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
                WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
                asyncManager.setTaskExecutor(this.taskExecutor);
                asyncManager.setAsyncWebRequest(asyncWebRequest);
                asyncManager.registerCallableInterceptors(this.callableInterceptors);
                asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
                //如果异步请求有结果了,就用异步的结果
                if (asyncManager.hasConcurrentResult()) {
                    Object result = asyncManager.getConcurrentResult();
                    mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                    asyncManager.clearConcurrentResult();
                    LogFormatUtils.traceDebug(logger, traceOn -> {
                        String formatted = LogFormatUtils.formatValue(result, !traceOn);
                        return "Resume with async result [" + formatted + "]";
                    });
                    invocableMethod = invocableMethod.wrapConcurrentResult(result);
                }
                //调用最终的处理方法
                invocableMethod.invokeAndHandle(webRequest, mavContainer);
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return null;
                }
    
                return getModelAndView(mavContainer, modelFactory, webRequest);
            }
            finally {
                webRequest.requestCompleted();
            }
        }
    

     方法的逻辑比较复杂,先看看简单的看看步骤:

    1. 获取请求处理类中贴有@InitBinder注解的方法,然后创建一个WebDataBinderFactory
    2. 获取请求处理类中贴有@ModelAttribute注解的方法,然后创建一个ModelFactory
    3. 将请求处理类封装为一个ServletInvocableHandlerMethod对象
    4. 设置请求参数解析器组合类
    5. 设置返回参数解析器组合类
    6. 设置前面封装@InitBinder注解的WebDataBinderFactory
    7. 设置方法跟构造器参数解析的类
    8. 创建视图容器ModelAndViewContainer,然后初始化并设置初始的一些模型
    9. 处理异步请求相关的
    10. 调用请求处理类,对应的处理方法。

      这里的步骤虽然多,但是还是可以简单的分为用户处理方法调用前的准备工作,跟调用处理方法两个步骤。这里对于准备的工作不做解析,主要看处理方法invokeAndHandle的调用。其余方法的逻辑后面会有文章进行介绍,这里就讲跟主题相关的。

    3.2.2 调用我们定义的controller类中的逻辑的步骤invokeAndHandle

     进入到invokeAndHandle方法

        public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
            //调用处理的方法,获取处理的结果
            Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
            //如果方法上有ResponseStatus注解,则按照我们设置的返回状态进行返回
            setResponseStatus(webRequest);
            //如果方法结果为null
            if (returnValue == null) {
                //如果请求没有修改过,或者返回状态不为null,或者请求得到处理了都会设置请求为已经处理的状态然后返回
                if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                    disableContentCachingIfNecessary(webRequest);
                    mavContainer.setRequestHandled(true);
                    return;
                }
            }
            else if (StringUtils.hasText(getResponseStatusReason())) {
                //设置请求为已经处理的状态
                mavContainer.setRequestHandled(true);
                return;
            }
    
            mavContainer.setRequestHandled(false);
            Assert.state(this.returnValueHandlers != null, "No return value handlers");
            try {
                //对返回的结果进行进一步的处理,这些都是一些扩展点
                this.returnValueHandlers.handleReturnValue(
                        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
            }
            catch (Exception ex) {
                if (logger.isTraceEnabled()) {
                    logger.trace(formatErrorForReturnValue(returnValue), ex);
                }
                throw ex;
            }
        }
    

    这里的逻辑就是调用处理方法,获取返回结果,如果处理结果是已经处理过的则直接返回,没有就处理过则对返回的结果进行进一步的处理。现在要继续看的是invokeForRequest方法。

        public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    
            //调用扩展的参数处理的逻辑,得到方法调用钱的参数
            Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
            if (logger.isTraceEnabled()) {
                logger.trace("Arguments: " + Arrays.toString(args));
            }
            //进行方法的调用
            return doInvoke(args);
        }
    
    
    
        @Nullable
        protected Object doInvoke(Object... args) throws Exception {
            ReflectionUtils.makeAccessible(getBridgedMethod());
            try {
                return getBridgedMethod().invoke(getBean(), args);
            }
            ......
    

     逻辑很简单就是调用自己扩展的参数处理方法,用处理过后的参数作为入参然后用反射调用定义的逻辑处理方法(就是我们controller中定义的方法),最后返回调用的结果。

     到这里整个HandlerAdapter的选择跟请求的处理逻辑就结束了。

    相关文章

      网友评论

          本文标题:spring源码------一个请求在spring中的处理过程(

          本文链接:https://www.haomeiwen.com/subject/thenohtx.html