Spring source code learning series 3.2-handlerAdapter execution

DispatcherServlet#doDispatch calls HandlerAdapter to actually execute user-defined business logic, that is, controller layer code

//1 Get 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 Determine if handlerAdapter is suitable for processing the handler
			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");
	}

For a certain system, only one handlerAdapter is generally used (ps: whether this place can be optimized), the following takes SimpleControllerHandlerAdapter as an example

Adapter Mode-Object Adapter Mode: -Delegate Relationship
In this adapter mode, the adapter accommodates a An instance of the wrapped class. In this case, the adapter calls the physics entity of the wrapped object.
https://en.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 Determine whether the handler is a Controller instance, and if so, return the handler
		return (handler instanceof Controller);
	}


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

//2.1 Call handleRequest of Controller interface-interface-oriented programming
		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 {
//Parse method parameters such as method=?
			String methodName = this.methodNameResolver.getHandlerMethodName(request);
//According to the method name, the instance method is called by reflection
			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 {

//Get the method execution body, handlerMethodMap is initialized in the constructor
		Method method = this.handlerMethodMap.get(methodName);
		if (method == null) {
			throw new NoSuchRequestHandlingMethodException(methodName, getClass());
		}

		try {
//Set the method parameters (the first two of the processing method must be request and response)
			Class[] paramTypes = method.getParameterTypes();
			List<Object> params = new ArrayList<Object>(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);
			}

//Set the command object property according to the request, if any -VS-model driven
			// 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);
			}

// call the method
			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);
		}
	}

The handlerMethodMap is cached during initialization.


How does springmvc set the command object according to the request?



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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326443259&siteId=291194637