Spring MVC处理请求源码分析

tech2022-09-18  103

《Spring Boot源码博客》

Spring MVC处理一个REST请求的过程如下

Spring MVC核心流程如下:

一、系统启动阶段初始化请求与Controller方法的映射集合。

二、根据请求查找对应的Controller方法。

三、解析请求参数,通过反射执行Controller方法。

四、处理返回结果。

一、初始化阶段

在初始化阶段需要了解几个Spring MVC组件

1、DispatcherServlet:为客户端的请求提供通用的处理方法,请求分发给各个处理器(Controller方法属于处理器)

2、HandlerMapping:是一个接口,定义请求和处理程序对象之间的映射关系。

2.1、 RequestMappingHandlerMapping:HandlerMapping的实现类,存储请求和Controller方法的映射关系。

2.1.1、RequestMappingInfo 封装了请求信息,HandlerMethod封装了Controller方法。例如:

@RequestMapping("/test2") public class Test2Controller { @GetMapping("/path/{userId}") public Result path(@PathVariable("userId") long userId) { } }

对于上面的代码。RequestMappingInfo保存请求类型GET、请求路径/test2/path/{userId}等信息。HandlerMethod保存着Test2Controller#path(Long)方法。

下图是Spring MVC处理请求的部分流程,DispatcherServlet接收请求,并使用RequestMappingHandlerMapping找出请求对应的Contoller方法:

上图左边的大橙色框,this.handlerMappings中的this是指DispatcherServlet,即handlerMappings是DispatcherServlet的属性。this.handlerMappings橙色框里面有个小的橙色框,表示RequestMappingHandlerMapping是this.handlerMappings列表的一个元素。

新建一个Controller,启动Spring MVC项目,探究Spring MVC初始化阶段做了什么。

1、在AbstractHandlerMethodMapping#processCandidateBean()打断点,启动Spring MVC。

/** * 创建bean时,会调用本方法。 * 若类上有@Controller或者@RequestMapping。执行detectHandlerMethods(beanName) */ protected void processCandidateBean(String beanName) { ...仅展示主要代码 // beanType是类Class // isHandler(beanType),Class上有@Controller或者@RequestMapping返回true if (beanType != null && isHandler(beanType)) { // 提取Controller类的url与方法的关系 detectHandlerMethods(beanName); } }

1.1、detectHandlerMethods(beanName)解析

/** * 源码位置 AbstractHandlerMethodMapping#detectHandlerMethods(java.lang.Object) * 在bean中查找处理程序方法 */ protected void detectHandlerMethods(Object handler) { ...仅展示主要代码 //寻找方法上有@RequestMapping注解的Method实例。 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { // 返回RequestMappingInfo对象 return getMappingForMethod(method, userType); }); //将获取到的Method对象注册到HandlerMapping中去 methods.forEach((method, mapping) -> { registerHandlerMethod(handler, invocableMethod, mapping); }); }

1.1.1、getMappingForMethod(method, userType)解析

/** * 使用方法和类上的@RequestMapping创建RequestMappingInfo */ protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // 先使用方法上的@RequestMapping信息创建RequestMappingInfo RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { // 再使用类上的@RequestMapping信息创建RequestMappingInfo RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { //将两个信息合并 info = typeInfo.combine(info); } String prefix = getPathPrefix(handlerType); if (prefix != null) { info = RequestMappingInfo.paths(prefix).build().combine(info); } } return info; }

1.1.2、registerHandlerMethod(handler, invocableMethod, mapping) 解析。在AbstractHandlerMethodMapping.MappingRegistry#register(java.lang.Object, java.lang.Object, java.lang.reflect.Method)方法中打断点

/** * 源码地址:AbstractHandlerMethodMapping.MappingRegistry#register(java.lang.Object, java.lang.Object, java.lang.reflect.Method) * RequestMappingHandlerMapping继承了AbstractHandlerMethodMapping * register(T mapping, Object handler, Method method)在RequestMappingHandlerMapping创建时执行 */ public void register(T mapping, Object handler, Method method) { ...仅展示主要代码 /** * handler是Controller类在IOC中的名字,例如test1Controller * method是Controller有@RequestMapping标注的方法 * 通过两者封装创建出HandlerMethod对象 */ HandlerMethod handlerMethod = createHandlerMethod(handler, method); /** * 创建及注册 MappingRegistration 信息 * this.registry是RequestMappingHandlerMapping.MappingRegistry#registry,是Map<T, MappingRegistration<T>>类型 * * mapping是RequestMappingInfo类型,存储请求信息 * MappingRegistration实例包含了Controller方法 * 至此,this.registry便是存储了请求信息和Controller方法的映射关系 */ this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); }

通过上面的的步骤,RequestMappingHandlerMapping实例便初始化好了。

接下来便是将RequestMappingHandlerMapping实例添加到DispatcherServlet的handlerMappings属性中,在DispatcherServlet#initStrategies()打断点调试。

1、DispatcherServlet#initStrategies()解析

/** * 源码位置:DispatcherServlet#initStrategies(org.springframework.context.ApplicationContext) * 初始化DispatcherServlet使用的策略对象 */ protected void initStrategies(ApplicationContext context) { //初始化文件上传处理器 initMultipartResolver(context); //初始化国际化配置 initLocaleResolver(context); //初始化主题处理器 initThemeResolver(context); //初始化HandlerMapping initHandlerMappings(context); //初始化HandlerAdapter //HandlerAdapter用来调用具体的方法对用户发来的请求来进行处理 initHandlerAdapters(context); //初始化异常处理器, // HandlerExceptionResolver是用来对请求处理过程中产生的异常进行处理 initHandlerExceptionResolvers(context); //RequestToViewNameTranslator用于在视图路径为空的时候,自动解析请求 //去获取ViewName initRequestToViewNameTranslator(context); //初始化视图处理器 //ViewResolvers将逻辑视图转成view对象 initViewResolvers(context); }

2、主要研究initHandlerMappings(context);方法

/** * 源码位置:DispatcherServlet#initHandlerMappings(org.springframework.context.ApplicationContext) * 初始化DispatcherServlet使用的HandlerMappings */ private void initHandlerMappings(ApplicationContext context) { ...仅展示主要代码 /** * 寻找IOC容器中为HandlerMapping类型的Bean * RequestMappingHandlerMapping便是HandlerMapping的实现类之一 */ Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { /** * 将HandlerMapping实现类集合赋值给DispatcherServlet的HandlerMappings属性 */ this.handlerMappings = new ArrayList<>(matchingBeans.values()); /** * 对找到的HandlerMapping类型的Bean列表进行排序 * 排序后,RequestMappingHandlerMapping排在第一位,首选它 */ AnnotationAwareOrderComparator.sort(this.handlerMappings); } }

二、根据请求查找对应的Controller方法

本小节需要了解以下组件:

HandlerExecutionChain:处理程序执行链,由处理程序对象和任何处理程序拦截器组成。

HandlerMethod:封装由Controller类、Controller类方法组成的信息,提供对方法参数、返回值、注解的便捷访问。

编写一个controller方法,接收 GET localhost:8080/test1/query?pageNum=1&pageSize=2 请求。

1、请求都会经DispatcherServlet#doService()处理。

1.1、在DispatcherServlet#doDispatch()方法中打断点。

/** * 源码位置: DispatcherServlet#doDispatch(HttpServletRequest, HttpServletResponse) * 向处理程序分派请求,所有的HTTP方法都由该方法处理。 * 通过HandlerMappings可以获取处理程序。 * 通过HandlerAdapters查询出能解析请求参数的HandlerAdapter */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ...仅展示主要代码 /** * HandlerExecutionChain * 处理程序执行链,由处理程序对象和任何处理程序拦截器组成。在本次请求中,由Controller方法和拦截器组成 */ HandlerExecutionChain mappedHandler = null; /** * 根据当前request获取handler,handler中包含了请求url,以及对应的controller、controller方法 */ mappedHandler = getHandler(processedRequest); // 通过handler获取对应的适配器,adapter负责完成参数解析 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); /** * 遍历所有定义的 interceptor,执行 preHandle 方法 */ if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 调用目标Controller方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); /** * 拦截器postHandle方法进行处理 */ mappedHandler.applyPostHandle(processedRequest, response, mv); // 处理最后的结果,渲染之类的逻辑都在这里 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); }

先关注获取HandlerExecutionChain的逻辑

    HandlerExecutionChain mappedHandler = null;     mappedHandler = getHandler(processedRequest);

1.1.1、DispatcherServlet#getHandler(HttpServletRequest request)方法解析。

/** * 源码位置: DispatcherServlet#getHandler(HttpServletRequest request) */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { /** * 循环this.handlerMappings,遍历得到的第一个mapping是RequestMappingHandlerMapping * 若HandlerMapping实现类的getHandler()的返回结果不为null,返回此handler */ for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }

1.1.1.1、RequestMappingHandlerMapping.getHandler(HttpServletRequest request)解析

/** * 源码位置: AbstractHandlerMapping#getHandler(HttpServletRequest request) * 获取处理器链 */ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { ...仅展示主要代码 //获取handler的具体逻辑由子类实现 Object handler = getHandlerInternal(request); //根据handler和request构建处理器链HandlerExecutionChain HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); return executionChain; }

1.1.1.1.1、Object handler = getHandlerInternal(request); debug这个方法,最终来到下面的代码中。

/** * 源码位置: AbstractHandlerMethodMapping#getHandlerInternal(HttpServletRequest request) */ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 获取 request 中的 url,用来匹配 handler String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // 根据路径寻找 Handler,并封装成 HandlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); // 根据 handlerMethod 中的 bean 来实例化 Handler,并添加进 HandlerMethod return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); }

handlerMethod如下图所示:

1.1.1.1.2、HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);解析。

/** * 源码位置: AbstractHandlerMapping.getHandlerExecutionChain(Object handler, HttpServletRequest request) * 构建处理器链HandlerExecutionChain */ protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { //判断handler是不是执行器链,如果不是则创建一个执行器链 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); // 添加拦截器 String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }

回到1.1步骤的代码中:

    // 创建处理程序执行链     HandlerExecutionChain mappedHandler = null;     mappedHandler = getHandler(processedRequest);     // 执行拦截器 preHandle 方法     if (!mappedHandler.applyPreHandle(processedRequest, response)) {         return;     }     // 执行拦截器postHandle方法     mappedHandler.applyPostHandle(processedRequest, response, mv);

这几行代码相信大家已经看懂了。

三、解析请求参数,反射执行Controller方法

解析请求参数

上面分析了通过请求找到对应的Controller方法,接下来分析如何解析请求参数。先了解几个组件:

HandlerAdapter:适配器,包含参数解析、返回值处理等功能。

HandlerMethodArgumentResolver:从request中解析出方法参数。

解析参数的类图如下:

1、在 DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response)处打断点。

/** * 源码位置: DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ...仅展示主要代码 /** * 前面已经分析过获取mappedHandler的过程了 */ /** * 获取HandlerAdapter * 最终返回RequestMappingHandlerAdapter */ HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // controller方法执行,并返回ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); }

1.1、HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 解析

/** * 源码位置: DispatcherServlet.getHandlerAdapter(Object handler) * 返回支持当前handler的HandlerAdapter */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { /** * 遍历所有的 HandlerAdapter,找到和当前 Handler 匹配的HandlerAdapter实例 * 遍历过程中,第一个HandlerAdapter是RequestMappingHandlerAdapter * * RequestMappingHandlerAdapter的supports方法代码如下: * public final boolean supports(Object handler) { * return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); * } * * 通过之前的代码分析得知,请求[ GET localhost:8080/test1/query?pageNum=1&pageSize=2 ]返回的handler是HandlerMethod类型, * 所以会返回RequestMappingHandlerAdapter */ for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }

1.2、mv = ha.handle(processedRequest, response, mappedHandler.getHandler());解析

/** * 源码位置: RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest request, * HttpServletResponse response, HandlerMethod handlerMethod) */ protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //把handlerMethod封装成ServletInvocableHandlerMethod ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { //设置参数解析器 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { //设置返回值处理器 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } //设置参数名称发现器 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); //核心逻辑,最终去执行Handler方法处理请求 invocableMethod.invokeAndHandle(webRequest, mavContainer); return getModelAndView(mavContainer, modelFactory, webRequest); }

1.2.1、invocableMethod.invokeAndHandle(webRequest, mavContainer);解析

/** * 源码位置: ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) * 调用Controller方法并通过HandlerMethodReturnValueHandler处理返回值 */ public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { ...仅展示主要代码 // 调用controller中的method方法 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 处理返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }

1.2.1.1、Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);解析

/** * 源码位置: InvocableHandlerMethod.invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) */ public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取controller方法实参 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } // 调用controller方法 return doInvoke(args); }

1.2.1.1.1、Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);解析

/** * 源码位置: InvocableHandlerMethod.getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) */ protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { ...仅展示主要代码 //获取Controller方法参数列表 MethodParameter[] parameters = getMethodParameters(); //创建一个参数数组,保存从request解析出的方法参数 Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; //给每一个Controller方法实例参数初始化一个参数名称发现器 parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); //解析并绑定参数的核心逻辑 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } return args; }

args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 这句代码是获取参数值的关键。this.resolvers默认有26个参数解析器。

RequestParamMethodArgumentResolver支持@RequestParam解析,使用request.getParameterValues(name)获取值。

RequestResponseBodyMethodProcessor支持@RequestBody解析,使用MappingJackson2HttpMessageConverter将RequestBody反序列化为javaBean。

1.2.1.2、doInvoke(args);解析

/** * 源码位置: InvocableHandlerMethod.doInvoke(Object... args) */ protected Object doInvoke(Object... args) throws Exception { ...仅展示主要代码 // 方法设置accessible ReflectionUtils.makeAccessible(getBridgedMethod()); // 调动方法 return getBridgedMethod().invoke(getBean(), args); }

四、处理返回结果

HandlerMethodReturnValueHandler:处理返回值。

/** * 源码位置: ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) * 调用Controller方法并通过 HandlerMethodReturnValueHandler处理返回值 */ public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { ...仅展示主要代码 /** * 前面已经分析了调用controller方法的代码 */ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); /** * 现在分析处理返回值的代码 */ this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }

1、this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);解析

/** * 源码位置: HandlerMethodReturnValueHandlerComposite.handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) * 返回值处理 */ @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { /** * 选择能处理返回值的HandlerMethodReturnValueHandler,通过HandlerMethodReturnValueHandler实现类的supportsReturnType(MethodParameter returnType)判断能否处理返回值 * 例如:RequestResponseBodyMethodProcessor的supportsReturnType(MethodParameter returnType)是判断类或方法有@ResponseBody则返回true */ HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); /** * 处理返回值 * RequestResponseBodyMethodProcessor会将Controller方法返回结果写入responseBody。 * 如果Controller方法返回ModelAndView,处理返回值的类是ModelAndViewMethodReturnValueHandler,此类将ModelAndView的属性设置给mavContainer */ handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }

2、回到RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 方法处。

/** * 源码位置: RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest request, * HttpServletResponse response, HandlerMethod handlerMethod) */ protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ...仅展示部分代码 /** * 生成ModelAndView */ return getModelAndView(mavContainer, modelFactory, webRequest); }

3、最后对response的处理。

/** * 源码位置: DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) * 处理最后的结果 */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ...仅展示部分代码 // 处理最后的结果,渲染之类的逻辑都在这里 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); }

 

 

最新回复(0)