SpringMVC之HanderAdapter

在上一篇HandlerMapping中,HandlerMapping在初始化时就将@RequestMapping对应的url与Controller建立了对应关系,前端的Http请求通过对应关系找到Controller,这就是HandlerMapping的使命,接下来就是HandlerAdapter来进行处理了。在HandlerMapping中有讲到DispatcherServlet的初始化中会调用initStrategies()方法,这里面也包含了HanderAdapter的初始化

initHandlerAdapters(context);
private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				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.
			}
		}

		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
			}
		}
	}

同HandlerMapping初始化一样,默认的HanderAdapter实现也是配置在DispatcherServlet.properties文件中

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

配置可以看出,HandlerAdapter默认有三种类型的实现,分别是:HttpRequestHandlerAdapterSimpleControllerHandlerAdapterAnnotationMethodHandlerAdapter

现在回到DispatcherServlet中来,看到请求处理的方法doDispatch()方法中有这么一段:

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这段就是通过HandlerMapping返回的Handler,来找到对应的Controller执行相应的逻辑,下面我们来具体看一下内部实现

//重点看一下AnnotationMethodHandlerAdapter的handler方法
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
        //获取class对象
		Class<?> clazz = ClassUtils.getUserClass(handler);
		//检查class对象是否含有SessionAttributes注解
		Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
		if (annotatedWithSessionAttributes == null) {
			annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
			this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
		}

		if (annotatedWithSessionAttributes) {
			checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
		}
		else {
			checkAndPrepare(request, response, true);
		}

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return invokeHandlerMethod(request, response, handler);
				}
			}
		}
		//重点是invoke方法来做的调用
		return invokeHandlerMethod(request, response, handler);
	}
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
        //我们知道handler就是从上一步HandlerMapping拿到的Controller,这里通过handler拿到HandlerMethodResolver
        //那HandlerMethodResolver到底是个什么鬼?它里面主要是存储Controller中方法上@RequestMapping的url以及所有的方法
		ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
		//通过methodResolver与当前的request进行匹配,通过请求的url找到需要调用的方法
		Method handlerMethod = methodResolver.resolveHandlerMethod(request);
		ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		ExtendedModelMap implicitModel = new BindingAwareModelMap();

        //重点看该方法调用,看下面具体源码
		Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
		ModelAndView mav =
				methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
		methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
		return mav;
	}
	
	public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

		Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
		try {
			boolean debug = logger.isDebugEnabled();
			for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
				Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
				if (attrValue != null) {
					implicitModel.addAttribute(attrName, attrValue);
				}
			}
			for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
				Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
				Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
				if (debug) {
					logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
				}
				String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
				if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
					continue;
				}
				ReflectionUtils.makeAccessible(attributeMethodToInvoke);
				Object attrValue = attributeMethodToInvoke.invoke(handler, args);
				if ("".equals(attrName)) {
					Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
					attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
				}
				if (!implicitModel.containsAttribute(attrName)) {
					implicitModel.addAttribute(attrName, attrValue);
				}
			}
			//这里即将调用方法的参数,对参数进行处理
			Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
			if (debug) {
				logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
			}
			ReflectionUtils.makeAccessible(handlerMethodToInvoke);
			//将参数传入,利用反射来进行方法调用
			return handlerMethodToInvoke.invoke(handler, args);
		}
		catch (IllegalStateException ex) {
			// Internal assertion failed (e.g. invalid signature):
			// throw exception with full handler method context...
			throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
		}
		catch (InvocationTargetException ex) {
			// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
			ReflectionUtils.rethrowException(ex.getTargetException());
			return null;
		}
	}

好,进行到这里已经调用完了方法,再回到上一步看看返回值的情况

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
        //我们知道handler就是从上一步HandlerMapping拿到的Controller,这里通过handler拿到HandlerMethodResolver
        //那HandlerMethodResolver到底是个什么鬼?它里面主要是存储Controller中方法上@RequestMapping的url以及所有的方法
		ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
		//通过methodResolver与当前的request进行匹配,通过请求的url找到需要调用的方法
		Method handlerMethod = methodResolver.resolveHandlerMethod(request);
		ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		ExtendedModelMap implicitModel = new BindingAwareModelMap();

        //进行方法调用返回Object
		Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
		//将返回的Object对象进行封装,返回ModelAndView给DispatcherServlet
		ModelAndView mav =
				methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
		//BindingResult、SessionAttribute等后续处理
		methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
		//处理完成,返回ModelAndView给Dispathcher
		return mav;
	}
	

下面来看一下ModelAndView是个啥?

//根据handler处理的结果,封装一个ModelAndView给前端
public ModelAndView getModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue,
				ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception {

			ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(handlerMethod, ResponseStatus.class);
			if (responseStatus != null) {
				HttpStatus statusCode = responseStatus.code();
				String reason = responseStatus.reason();
				if (!StringUtils.hasText(reason)) {
					webRequest.getResponse().setStatus(statusCode.value());
				}
				else {
					webRequest.getResponse().sendError(statusCode.value(), reason);
				}

				// to be picked up by the RedirectView
				webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, statusCode);

				this.responseArgumentUsed = true;
			}

			// Invoke custom resolvers if present...
			if (customModelAndViewResolvers != null) {
				for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) {
					ModelAndView mav = mavResolver.resolveModelAndView(
							handlerMethod, handlerType, returnValue, implicitModel, webRequest);
					if (mav != ModelAndViewResolver.UNRESOLVED) {
						return mav;
					}
				}
			}
            //以下是判断返回值的各种类型,给出不同的处理
			if (returnValue instanceof HttpEntity) {
				handleHttpEntityResponse((HttpEntity<?>) returnValue, webRequest);
				return null;
			}
			//@ResponseBody注解的处理
			else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
				handleResponseBody(returnValue, webRequest);
				return null;
			}
			//看这里,就是我们很熟悉的ModelAndView的处理
			else if (returnValue instanceof ModelAndView) {
				ModelAndView mav = (ModelAndView) returnValue;
				mav.getModelMap().mergeAttributes(implicitModel);
				return mav;
			}
			//返回Model
			else if (returnValue instanceof Model) {
				return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap());
			}
			//返回View
			else if (returnValue instanceof View) {
				return new ModelAndView((View) returnValue).addAllObjects(implicitModel);
			}
			//@ModelAttribute注解的处理
			else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {
				addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
				return new ModelAndView().addAllObjects(implicitModel);
			}
			//返回Map
			else if (returnValue instanceof Map) {
				return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map<String, ?>) returnValue);
			}
			//返回String
			else if (returnValue instanceof String) {
				return new ModelAndView((String) returnValue).addAllObjects(implicitModel);
			}
			//返回null的处理
			else if (returnValue == null) {
				// Either returned null or was 'void' return.
				if (this.responseArgumentUsed || webRequest.isNotModified()) {
					return null;
				}
				else {
					// Assuming view name translation...
					return new ModelAndView().addAllObjects(implicitModel);
				}
			}
			else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) {
				// Assume a single model attribute...
				addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
				return new ModelAndView().addAllObjects(implicitModel);
			}
			else {
				throw new IllegalArgumentException("Invalid handler method return value: " + returnValue);
			}
		}

总结一下:

  1. HanderAdapter从上一步HandlerMapping拿到Controller
  2. 通过Controller,经过反射拿到Controller中@requestMapping上url与方法的对应关系,返回ServletHandlerMethodResolver
  3. 通过request请中的url与ServletHandlerMethodResolver中的mappings匹配,可以找到需要调用的方法
  4. 利用反射调用找到的方法,返回Object
  5. 处理返回结果,根据不同的返回值类型(ModelAndView、String、Map、View等)进行处理后,封装成ModelAndView返回给前台
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值