这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
SpringMVC的执行流程其实重点就是DispatcherSerlvet、handlermappings,handlerAdapter,viewResolver之间的交互。
流程梗概如下:
-
所有的请求会打到DispatcherSerlvet上。
- DispatcherSerlvet是一个HTTPServlet,SpingMVC所有的请求都打在这个Servlet上。
-
DispatcherServlet会遍历所有的handlerMappings找到对应的handler并获取到HandlerExecutionChain
- handlermappings的作用是依据请求的url找到对应的handler,也就是该url对应的方法。
- 这里面主要有3个handlermappings:分别对应的controller的三种实现
- spring mvc 有两大类型,三种方式实现controller层
- 两大类型
- BeanName方式:以BeanName来作为url。
- RequestMapping方式:RequestMapping注解方式标注url。
- 三种方式
-
实现controller接口+component注解 (beanName就是path)。
-
实现HttpRequestHandler接口+component注解(beanName就是path)。
-
Controller注解和RequestMapping注解。(最多的是用这种)
-
- 两大类型
- spring mvc 有两大类型,三种方式实现controller层
- 这里面主要有3个handlermappings:分别对应的controller的三种实现
- HandlerExecutionChain 这个handler执行链对象就是请求路径对应controller的方法封装的对象HandlerMethod,和一个拦截器list。
- handlermappings的作用是依据请求的url找到对应的handler,也就是该url对应的方法。
-
上面的HandlerExecutionChain会接着遍历handlerAdapters找到对应的handlerAdapter 并包装为获取HandlerAdapter(后续的操作都是这个Adapter在操作)
- 为什么需要这些Adapter?
- 上面也说了,controller是可以有多种方式实现的。那么不同方式去调用对应方法的方式也是不一样的!
- 问:Java调用另外一个类的方式
- new对象调用(不可取,SpringMVC不可能动态知道调用哪个方法-没法写死在代码里面)
- 接口调用(定死一个接口,代码里面直接调接口方法,但是灵活度就差了,只能少量定死的接口方法)
- 反射调用(灵活度高,效率差)
- SpringMVC实现
- BeanName方式的controller实现,用的是接口的方式
- RequestMapping方式用的是反射
- 如果不加这些Adapter的话,就需要一堆的if-else去判断了。定义这些Adapter可以适应各种场景!
- 问:Java调用另外一个类的方式
- 上面也说了,controller是可以有多种方式实现的。那么不同方式去调用对应方法的方式也是不一样的!
- 为什么需要这些Adapter?
-
HandlerAdapter 最终会调用handle方法执行对应controller的方法并返回ModelAndView。
-
这个handler会从request拿取到参数,然后通过反射到的Method对象,遍历参数列表,并通过一系列的参数解析器(类似于RequestParam/Path等等这些就是通过解析器来解析的)将参数解析到方法对应的实参,最后invoke调用controller的方法。
-
番外:springMVC是基于反射调用方法的,JDK8之前,反射是无法获取到参数名称的,参数都会被简化为arg0..n,SpringMVC是基于ASM字节码方式去拿的(1.8之后,开启-parameters就可以拿到)。所以说:SpringMVC还可以根据参数名自动匹配,不需要写requstparm这些注解。
- 解析参数:1. 优先是注解的 2. 然后JDK反射的-只针对1.8+ 3. 无奈只能ASM的。
-
如果controller方法加了@ReponseBody注解,那么modelAndView会直接返回null,就直接返回到response,不会再走下面的视图解析过程了。
-
DispatcherSerlvet获取到ModelAndView交给视图解析器ViewResolver,解析器会将其解析成view。
-
DispatcherServlet根据获取到View进行视图渲染,并将视图返回给用户。