spring源码解析-web系列(四):九大组件之HandlerAdapter

spring源码解析-web系列(一):启动
spring源码解析-web系列(二):处理请求的过程
spring源码解析-web系列(三):九大组件之HandlerMapping
spring源码解析-web系列(四):九大组件之HandlerAdapter
spring源码解析-web系列(五):解析请求参数
spring源码解析-web系列(六):九大组件之ViewResolver
spring源码解析-web系列(七):九大组件之HandlerExceptionResolver

转载请标明出处:
https://blog.csdn.net/bingospunky/article/details/98463628
本文出自马彬彬的博客

HandlerAdapter

HandlerMapping通过request找到Handler,HandlerAdapter通过Handler来干活。HandlerAdapter的继承关系如下:

图1:

https://qingtian-blog.oss-cn-beijing.aliyuncs.com/spring%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-web%E7%B3%BB%E5%88%97%28%E5%9B%9B%29%3A%E4%B9%9D%E5%A4%A7%E7%BB%84%E4%BB%B6%E4%B9%8BHandlerAdapter_1.png

HandlerAdapter的继承结构很简单,且右边4个类都很简单,只需关注AbstractHandlerMethodAdapter和RequestMappingHandlerAdapter即可。

左边的AbstractHandlerMethodAdapter抽象了supportsInternal、handleInternal、getLastModifiedInternal三个方法,实现了Ordered,其他都交给了子类RequestMappingHandlerAdapter来实现。

HandlerAdapter通过Handler来干活,但是Handler的类型是多种多样的,并且会处理参数、处理异常等工作,所以RequestMappingHandlerAdapter的实现很复杂,是这九大组件中最复杂的一个。

RequestMappingHandlerAdapter初始化过程

初始化在afterPropertiesSet方法中:

代码1 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.afterPropertiesSet):

    public void afterPropertiesSet() {
        this.initControllerAdviceCache();
        List handlers;
        if (this.argumentResolvers == null) {
            handlers = this.getDefaultArgumentResolvers();
            this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.initBinderArgumentResolvers == null) {
            handlers = this.getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolver1s(handlers);
        }

        if (this.returnValueHandlers == null) {
            handlers = this.getDefaultReturnValueHandlers();
            this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
        }

    }

代码1第2行处理被@ControllerAdvice注解的bean。

代码2 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.initControllerAdviceCache):

	private void initControllerAdviceCache() {
        if (this.getApplicationContext() != null) {
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Looking for @ControllerAdvice: " + this.getApplicationContext());
            }

            List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(this.getApplicationContext());
            OrderComparator.sort(beans);
            List<Object> responseBodyAdviceBeans = new ArrayList();
            Iterator var3 = beans.iterator();

            while(var3.hasNext()) {
                ControllerAdviceBean bean = (ControllerAdviceBean)var3.next();
                Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
                if (!attrMethods.isEmpty()) {
                    this.modelAttributeAdviceCache.put(bean, attrMethods);
                    this.logger.info("Detected @ModelAttribute methods in " + bean);
                }

                Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
                if (!binderMethods.isEmpty()) {
                    this.initBinderAdviceCache.put(bean, binderMethods);
                    this.logger.info("Detected @InitBinder methods in " + bean);
                }

                if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                    responseBodyAdviceBeans.add(bean);
                    this.logger.info("Detected ResponseBodyAdvice bean in " + bean);
                }
            }

            if (!responseBodyAdviceBeans.isEmpty()) {
                this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
            }

        }
    }

代码2第7行获取到BeanFactory里所有被@ControllerAdvice注解的bean,后面遍历处理每一个bean。代码2第14行获取一个@ControllerAdvice注解的bean的所有被@ModelAttribute注解且没有被@RequestMapping注解的方法,放到modelAttributeAdviceCache中。代码2第20行代码获取一个@ControllerAdvice注解的bean的所有被@InitBinder注解的方法,放到initBinderAdviceCache中。代码2第26~29行,如果该bean是ResponseBodyAdvice类,则把该bean添加到responseBodyAdviceBeans中。由于@ControllerAdvice是全局的,这些方法被添加在适当的Map中,当请求到来时,可以方便的取出来使用。

代码1第4~第17行,分别处理argumentResolvers、initBinderArgumentResolvers、returnValueHandlers,他们过程相似,我们只看returnValueHandlers。

代码3 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.getDefaultArgumentResolvers):

	private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList();
        resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
        resolvers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters()));
        resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters()));
        resolvers.add(new RequestHeaderMethodArgumentResolver(this.getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        resolvers.add(new ServletCookieValueMethodArgumentResolver(this.getBeanFactory()));
        resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory()));
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
        resolvers.add(new HttpEntityMethodProcessor(this.getMessageConverters()));
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        resolvers.add(new ModelMethodProcessor());
        resolvers.add(new MapMethodProcessor());
        resolvers.add(new ErrorsMethodArgumentResolver());
        resolvers.add(new SessionStatusMethodArgumentResolver());
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
        if (this.getCustomArgumentResolvers() != null) {
            resolvers.addAll(this.getCustomArgumentResolvers());
        }

        resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));
        return resolvers;
    }

代码3添加了很多个HandlerMethodArgumentResolver用来解析参数。

RequestMappingHandlerAdapter执行过程

RequestMappingHandlerAdapter的执行就是实现父类的handleInternal方法:

代码4 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal):

    protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
        } else {
            this.checkAndPrepare(request, response, true);
        }

        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                    return this.invokeHandleMethod(request, response, handlerMethod);
                }
            }
        }

        return this.invokeHandleMethod(request, response, handlerMethod);
    }

代码4第2~第6行根据方式上是否被@SessionAttribute注解,来设置HttpServletResponse相关的header,与是否缓存相关的header(Expires、Cache-Control、max-age=xxx)。这部分是@SessionAttribute相关的,由于无状态的趋势,在实际开发中不使用@SessionAttribute,这部分可以先不关注。

代码5 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod):

    private ModelAndView invokeHandleMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);

		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
		ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		final 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();

			if (logger.isDebugEnabled()) {
				logger.debug("Found concurrent result value [" + result + "]");
			}
			requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
		}

		requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		return getModelAndView(mavContainer, modelFactory, webRequest);
	}

代码5第6行创建binderFactory对象,代码5第7行创建modelFactory对象,这俩对象是参数相关的,比如@ModelAttribute、@InitBinder等,注意这几个对象与@RequestParam、@PathVariabl等在http请求获取的参数无关。代码5第8行创建了ServletInvocableHandlerMethod对象,这个对象继承HandlerMethod,请求的处理就是通过这个对象执行的,包括参数绑定、请求处理、返回值解析等。代码5第10行创建了ModelAndViewContainer对象,这个对象贯穿处理的过程。代码5第11~第13行对ModelAndViewContainer进行了一些处理。代码5第35行执行处理过程。代码5第41行进行一些后置的处理,比如@SessionAttribute、RedirectAttribures,创建了ModelAndView对象。

ModelAndViewContainer

ModelAndViewContainer承担处理过程中数据的传递工作,它保存了View以及Model。
它有如下两个属性:

代码6 (org.springframework.web.method.support.ModelAndViewContainer):

	private final ModelMap defaultModel = new BindingAwareModelMap();
	private ModelMap redirectModel;

defaultModel是默认使用的Model,后者是redirect时使用的Model。我们在@RequestMapping方法里使用的Model或者ModelMap类型的对象就是他们。

ModelFactory

在RequestMappingHandlerAdapter.invokeHandleMethod方法的执行过程中使用了ModelFactory。

ModelFactory是用来维护Model的,具体包含两个功能:1.初始化Model。2.处理器执行后把Model中相应的参数更新到SessionAttributes中。

初始化Model的过程如下:

代码7 (org.springframework.web.method.annotation.ModelFactory.initModel):

	public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
			throws Exception {

		Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
		mavContainer.mergeAttributes(sessionAttributes);

		invokeModelAttributeMethods(request, mavContainer);

		for (String name : findSessionAttributeArguments(handlerMethod)) {
			if (!mavContainer.containsAttribute(name)) {
				Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
				if (value == null) {
					throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
				}
				mavContainer.addAttribute(name, value);
			}
		}
	}

初始化Model的过程分为3步:1.从SessionAttributes取出参数,存放到mavContainer中。2.执行注释了@ModelAttribute注释的方法,并将返回值设置到Model。3.处理既注释了@ModelAttribute又在@SessionAttribute中的参数。

ServletInvocableHandlerMethod

代码5第8行创建了ServletInvocableHandlerMethod对象,请求的处理就是通过这个对象触发的。
ServletInvocableHandlerMethod的继承关系比较简单,只有三层:ServletInvocableHandlerMethod -> InvocableHandlerMethod -> HandlerMethod 。

ServletInvocableHandlerMethod的执行过程如下:

代码8 (org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle):

	public void invokeAndHandle(ServletWebRequest webRequest,
			ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(this.responseReason)) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}

代码8第4行调用父类的invokeForRequest方法处理请求,获取的对象returnValue。代码8第20行处理返回的对象,并根据情况来渲染,根据returnValueHandler是否支持来决定是否渲染,这里有17个returnValueHandler,如果是不支持的类型,则不渲染。比如:ResponseEntity类型的返回值可以渲染;@ResponseBody注解的方法可以渲染;字符串类型不可以渲染;void类型不可以渲染。如果渲染完的话,会在mavContainer对象做如下标记***mavContainer.setRequestHandled(true);***,那么后面就不会再次渲染了。如果这里没有渲染,后面会在DispatcherServlet.processDispatchResult方法渲染。

代码8第4行调用父类的invokeForRequest方法如下:

代码9 (org.springframework.web.method.support.InvocableHandlerMethod):

	public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	    Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);

	    Object returnValue = this.doInvoke(args);
	    
	    return returnValue;
	}

	protected Object doInvoke(Object... args) throws Exception {
	    ReflectionUtils.makeAccessible(this.getBridgedMethod());

	    return this.getBridgedMethod().invoke(this.getBean(), args);
	}

代码9第2行获取参数。代码9第4行调用doInvoke方法,通过反射执行我们配置的Controller方法。

参数的解析是在ServletInvocableHandlerMethod类里执行的,我们在下一篇博客里专门阐述Spring是如何解析参数的。

总结

HandlerAdapter的作用就是通过前面获取到的Handler,执行处理逻辑。整个处理过程可以分为三步:解析参数、执行请求、处理返回值。

参数的来源有很多,大体可以分为两类,一类从Model中来,通过FlashMapManager和ModelFactory管理。另一类从request中来,使用HandlerMethodArgumentResolver解析,下一篇博客会详细介绍。

执行请求的是HandlerMethod的子类ServletInvocableHandlerMethod。

返回值是通过HandlerMethodReturnValueHandler进行解析的,不同返回值类型对应不同的HandlerMethodReturnValueHandler,在ServletInvocableHandlerMethod里进行解析。

另外,整个处理过程中ModelAndViewContainer起到传递参数的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值