SpringMvc源码记录之请求执行流程

2 篇文章 0 订阅

SpringMvc启动以及加载过程中以及讲到Spring启动加载过程,现在看下以及请求进来的过程以及数据流转过程,首先在看源码之前简单对SpringMvc请求过程有一个简单的大方向的了解:

 第一步就是获取,然后在Web Spring获取后根据request 中url来从HandlerMap查询Handler

第二步

  1. 请求数据经过DispatchServerlet
  2. 通过request 获取url查询Handler
  3. Handler调用相应的 Controller方法获取结果
  4. 组装成ModelAndView
  5. ModelAndView解析成view
  6. 返回给客户端

可以看到DispatchServlet是控制整过的控制者,以及逻辑分发者接下在再看下该类的UML图,可以看到这个类主要是Spring以及Servlet的一个桥梁既有实现接口Servlet相关的接口,也有Spring相关的接口,一开始主要这里主要涉及Servlet接口相关的。从UML图可以看到它是HttpServlet的子类,那么他有一个很重要的一个性质接受用户的请求,web配置的URL请求拦截的请求都会通过该类的

void service(HttpServletRequest req, HttpServletResponse resp)

方法处理。从代码上看,这个类的service方法主要通过父类FrameWorkServlet实现:

FrameWorkServlet.service:


	/**
	 * Override the parent class implementation in order to intercept PATCH requests.
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        //获取请求方法:POST  GET PUT 等
		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
			processRequest(request, response);
		}
		else {
            //调用HttpServlet service方法
			super.service(request, response);
		}
	}

再看下父类HTTPServlet的方法:

 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        //获取不同的请求方法类型
        String method = req.getMethod();

        //根据不同的请求类型走不同的方法
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
    

这块代码功能很简单就是获取请求的  方法类型,不同的请求类型走不同的逻辑,这些可以交给子类实现,这里用了模板模式,在FrameServlet重写了些 doGet  doPost方法:

	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

每一个方法最后都会调用processRequest这个方法,而这个方法最核心的是调用了

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
      throws Exception;

这个方法被DispatchServlet实现了,也就是说:一个请求过来最终的公共逻辑会走到DispatchServlet#doService方法

接下来就是真正的逻辑开始了。这个方法看代码其实最核心的调用

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception 

所以我们直接从这个方法开始看:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
                //将请求转化解析,如果是文件上传的请求
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
                //获取处理Handler(重点)
				mappedHandler = getHandler(processedRequest);
                //没有找到Handler  说明404啦
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
                //获取一个适配器(重点)
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
                //这里执行所有的和这个请求有关的拦截器,执行preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
                //适配器调用Handler方法,处理请求以及Handler,获取modelAndView
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
                //这里执行所有的和这个请求有关的拦截器,执行postHandle方法
				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

这里我们重点关注一下几个过程:

  1. 获取MapHandler过程,以及这个对象包含的信息
  2. HandlerAdapter执行过程
  3. HandlerAdapter角色作用

接下来我看从这三个方面来看下,下面都是基于注解的方式来走的(@Controller @RequestMapping)

MapHandler的获取

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
            //从HandlerMapping中获取Handler
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

在this.handlerMappings代表配置不同的类型,我们直接看debug的截图:

可以看到有三个HandlerMapping,其中SimpleUrlHandlerMapping是配置加载的,BeanNameURLHandlerMapping是默认实现的,RequestMappingHandlerMapping是基于@Controller @RequestMapping实现的。所以我们只用了注解实现的,我们只关心这块逻辑就好。接下来看下Mapping的getHandler方法:

@Override
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //获取一个Handler对象
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}
        //获取这个请求相关的拦截器,并且和Handler组装成一个对象
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}

以上代码只完成两个事情:获取一个请求相关的Handler  以及拦截器,看下这两个方法:

获取Handler

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //获取请求URL
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
        //加一个共享锁
		this.mappingRegistry.acquireReadLock();
		try {
            //获取HandlerMethod
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			if (logger.isDebugEnabled()) {
				if (handlerMethod != null) {
					logger.debug("Returning handler method [" + handlerMethod + "]");
				}
				else {
					logger.debug("Did not find handler method for [" + lookupPath + "]");
				}
			}
            //生成创建Handler
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}



protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<Match>();
        //获取一个Match对象,在下面看下这个debug数据内容(标注1)
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
            //把可以和这个匹配的Match对象加入一个List中(标注2)
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		if (!matches.isEmpty()) {
            //把刚刚的Matches排序(标注3)
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			Collections.sort(matches, comparator);
			if (logger.isTraceEnabled()) {
				logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
						lookupPath + "] : " + matches);
			}
            //获取最优的Match
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				if (CorsUtils.isPreFlightRequest(request)) {
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				Match secondBestMatch = matches.get(1);
                //有两个一样Match,那么就会抛出异常
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
							request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
				}
			}
			handleMatch(bestMatch.mapping, lookupPath, request);
            //返回Match的handlerMethod
			return bestMatch.handlerMethod;
		}
		else {
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
		for (T mapping : mappings) {
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
                //将拿到的match和mapping包装成一个对象
				matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
			}
		}
	}

上面两个方法主要获取Handler的过程:

  1. 首先获取T泛型集合(这个T是一个啥)
  2. 将Match集合排序获取最优的(是啥排序策略)
  3. 返回最优Match.Handler(这个又是一个啥)

上面我们知道了这个过程,但是对里面的数据却没有一个感性的认识,现在直接看debug数据就行。

首先看下标注1,获取一个List,其实是从this.urlLookup这个Map中获取的:

 这个数据结构内容是,key放的是我们的Url,value是一个list,list的每一个对象是怎么来的呢?其实这个数据来源就是注解@RequestMapping中各个转化的内容,也就是一个出现多个一样的的Url的处理方法(后面会有如何选其中的一个方法)。回答第一个问题,T是一个包含了注解信息的对象,包括 url Post/Get  等

然后就到了注解2,把我们刚刚拿到的所有的注解的信息会构造一个Match,拿着之前注解信息还会从this.mappingRegistry获取一个Handler。

我们可以看到获取的value是一个HandlerMethod对象,它是记录的主要是方法的信息,例如这个url对应的Controller bean  Method,以及方法的参数信息(第三个对象答案)。也就是一个Match对象有一个@RequestMapping注解信息以及方法的信息

接下来看下标注3,标注3主要对多个Match进行选取最优的Match,有两个最优的那么就会抛异常,我们从代码获取比较器一步步走进去我们可以看到最终是按照@RequestMapping信息对象(RequestMappingInfo)来排序的(上面第二个问题的答案),,这里就不详细看了,里面代码比较简单。

以上就是获取Handler的逻辑:

  1. 根据URL获取注解的信息对象
  2. 根据注解信息对象获取具体的方法信息对象
  3. 根据注解信息对象排序选出最优的哪一个方法信息Handler  返回,反之就会抛异常

         HandlerInterceptor获取

在获取完Handler后获取拦截器,组装成 HandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                   //拦截器可以匹配URL,就会加入到链表中
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

 

HandlerAdapter

我们在上面一部已经获取了URL对应的Handler,里面主要的要的处理的方法信息,这个请求交给哪一个Controller的哪一个方法,现在HandlerAdapter其实起的是一个执行的过程,以及提供各种上下文的对象完成数据映射转换,并且调用方法完成业务逻辑

/**
	 * Return the HandlerAdapter for this handler object.
	 * @param handler the handler object to find an adapter for
	 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
	 */
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
            //获取可以支持的适配器,这个和controller配置有关系,注解实现的返回RequestMappingHandlerAdapter
			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");
	}

这里按照注解实现那么就会返回RequestMappingHandlerAdapter,从主流程handle->handleInternal->invokeHandlerMethod方法:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);//构建执行器
			//设置请求参数到Controller转换对象
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            //设置返回值参数转换对象		invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            //设置参数绑定对象
			invocableMethod.setDataBinderFactory(binderFactory);

			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			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();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
            //执行方法
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}
            //生成modelAndView
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

上面的流程就是通过Handler以及上下文一些工具对象(各种Convert类)构建一个新的执行类进行执行。

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) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		try {
            //对返回的参数进行转换写入到Response中
			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;
		}
	}
	public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //转化获取controller需要的值
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"' with arguments " + Arrays.toString(args));
		}
        //通过反射调用bean的处理方法,拿到返回值
		Object returnValue = doInvoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"] returned [" + returnValue + "]");
		}
		return returnValue;
	}

上面的逻辑主要分为两步:

  1. 获取controller方法执行的参数
  2. 通过反射执行方法

接下来看下参数的获取过程:

	private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //获取controller参数信息
		MethodParameter[] parameters = getMethodParameters();
		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = resolveProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
            //查找该参数能支持的转化获取的类
			if (this.argumentResolvers.supportsParameter(parameter)) {
				try {//获取转化需要的值
					args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
					continue;
				}
				catch (Exception ex) {
					if (logger.isDebugEnabled()) {
						logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
					}
					throw ex;
				}
			}
			if (args[i] == null) {
				throw new IllegalStateException("Could not resolve method parameter at index " +
						parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
						": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
			}
		}
		return args;
	}

这一步主要识别一些根据参数以及标记例如注解等来拿到 HandlerMethodArgumentResolver 对象,例如参数带了 @RequestJsonbody 会有一个专门的类RequestResponseBodyMethodProcessor 来获取参数,带了@RequestParam 会有RequestParamMethodArgumentResolver类来获取参数。

还要一部就是在拿到返回值对返回值也有一个类似的转化的流程在

invokeAndHandle->this.returnValueHandlers.handleReturnValue

中,会调用

@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}



	private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
		boolean isAsyncValue = isAsyncReturnValue(value, returnType);
		for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
			if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
				continue;
			}
			if (handler.supportsReturnType(returnType)) {
				return handler;
			}
		}
		return null;
	}

这里如果通过拿到返回值得信息,例如注解,类等信息,决定拿到哪一个

HandlerMethodReturnValueHandler

来处理返回值。

 

以上就是主要的流程,回顾一下:

  1. 获取Servlet请求
  2. 获取请求 Url获取具体符合的方法集合
  3. 选取最优的方法
  4. 获取转换的Controller方法的执行参数
  5. 反射执行
  6. 获取结果,并且转换设置到Response中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值