spring源码学习系列3.2-handlerAdapter执行

阅读更多
DispatcherServlet#doDispatch中调用HandlerAdapter来真正执行用户定义的业务逻辑,即controller层代码

//1 获取handlerAdapter
// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

//2 执行handlerAdapter.handle
// 以UserController extends MultiActionController extends AbstractController extends WebContentGenerator为例
// Actually invoke the handler.
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());


DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
// 1.1 判断handlerAdapter是否适合处理该处理器
			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");
	}

对于某个系统而言,handlerAdapter一般只用到一种(ps:这个地方是否可以优化),以下以SimpleControllerHandlerAdapter为例

适配器模式-对象适配器模式:-委托关系
在这种适配器模式中,适配器容纳一个它包裹的类的实例。在这种情况下,适配器调用被包裹对象的物理实体。
https://zh.wikipedia.org/wiki/%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F


SimpleControllerHandlerAdapter#support
public boolean supports(Object handler) {
// 1.1.1 判断处理器是否是Controller实例,如果是则返回该handler
		return (handler instanceof Controller);
	}


SimpleControllerHandlerAdapter#handle
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

//2.1 调用Controller接口的handleRequest-面向接口编程
		return ((Controller) handler).handleRequest(request, response);
	}



AbstractController#handleRequest
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		// Delegate to WebContentGenerator for checking and preparing.
		checkAndPrepare(request, response, this instanceof LastModified);

		// Execute handleRequestInternal in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return handleRequestInternal(request, response);
				}
			}
		}

		return handleRequestInternal(request, response);
	}



MultiActionController#handleRequestInternal
@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
//解析方法参数如method=?
			String methodName = this.methodNameResolver.getHandlerMethodName(request);
//根据方法名称,反射调用实例方法
			return invokeNamedMethod(methodName, request, response);
		}
		catch (NoSuchRequestHandlingMethodException ex) {
			return handleNoSuchRequestHandlingMethod(ex, request, response);
		}
	}


MultiActionController#invokeNamedMethod
protected final ModelAndView invokeNamedMethod(
			String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {

//获取方法执行体,handlerMethodMap在构造函数里面初始化
		Method method = this.handlerMethodMap.get(methodName);
		if (method == null) {
			throw new NoSuchRequestHandlingMethodException(methodName, getClass());
		}

		try {
//设置方法参数(处理方法前面2个必须是request和response)
			Class[] paramTypes = method.getParameterTypes();
			List params = new ArrayList(4);
			params.add(request);
			params.add(response);

			if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {
				HttpSession session = request.getSession(false);
				if (session == null) {
					throw new HttpSessionRequiredException(
							"Pre-existing session required for handler method '" + methodName + "'");
				}
				params.add(session);
			}

//根据request设置command对象属性,如果有的话-VS-模型驱动
			// If last parameter isn't of HttpSession type, it's a command.
			if (paramTypes.length >= 3 &&
					!paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {
				Object command = newCommandObject(paramTypes[paramTypes.length - 1]);
				params.add(command);
				bind(request, command);
			}

// 调用方法
			Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));
			return massageReturnValueIfNecessary(returnValue);
		}
		catch (InvocationTargetException ex) {
			// The handler method threw an exception.
			return handleException(request, response, ex.getTargetException());
		}
		catch (Exception ex) {
			// The binding process threw an exception.
			return handleException(request, response, ex);
		}
	}

handlerMethodMap在初始化时缓存起来


springmvc 如何根据request设置command对象?



参考:
How to perform Spring validation in MultiActionController?
https://stackoverflow.com/questions/2744587/how-to-perform-spring-validation-in-multiactioncontroller

你可能感兴趣的:(spring)