主题介绍 -- SpringMVC源码分析
意义
-
通过阅读优秀的框架源码,可以深入理解框架的设计和实现原理,学习优秀的编程实践和设计模式。
-
框架通常是由经验丰富的开发人员设计和实现的,它们涉及到许多优秀的编程实践和设计模式。通过阅读框架源码,可以学习到这些实践和模式,并将其应用到自己的项目中,提升自己的代码水平和编程能力。
SpringMVC
Spring MVC
是基于Servlet API
构建的Web框架,是Spring
框架的一部分。
Spring MVC
是一个Web框架,平常所说的MVC
是一种后端架构,而SpringMVC
是基于MVC模式在 C [Controller]
这一层上的一种实现框架,比如以前的Struts
框架等等,再到早期的Servlet
,都属于MVC里面的C这一层的实现技术。SpringMVC
是对Servlet
的封装。
Spring Boot
只是简化了配置,如果你需要构建 MVC
架构的 Web
程序,你还是需要使用 Spring MVC
作为 MVC
框架,只是说 Spring Boot
帮你简化了 Spring MVC
的很多配置,做到开箱即用
SpringMVC组件介绍
-
DispatcherServlet
:DispatcherServlet
是SpringMVC
中的前端控制器,DispatcherServlet
是整个流程控制的中心,由它调用其它组件处理用户的请求,负责接收request
并将request
转发给对应的处理组件。 -
HandlerMapping
:HanlerMapping
处理器映射是SpringMVC
中完成url
到Controller
映射的组件。 -
Handler
:处理器,相当于是平常业务代码中每个请求对应的的controller
类以及方法信息,是SpringMVC
中负责处理request
的组件。 -
ModelAndView
:是封装结果视图的组件。 -
ViewResolver
:视图解析器,解析ModelAndView
对象,并返回对应的视图View
给客户端。ViewResolver
的主要作用是将控制器返回的逻辑视图名(例如 "home
"、"error
" 等)解析为具体的视图对象(例如JSP
、Thymeleaf
模板等),然后由DispatcherServlet
使用这些视图对象来渲染最终的视图内容。但在前后端分离的项目中,由于控制器不再返回视图名,而是直接返回数据,因此ViewResolver
的传统用法变得多余。
SpringMVC处理流程:
-
首先,请求进入
DispatcherServlet
,由DispatcherServlet
从HandlerMapping
中提取对应的Handler
。 -
此时,只是获取到了对应的
Handler
,然后得去寻找对应的适配器,即:HandlerAdapter
。 -
拿到对应的
HandlerAdapter
后,开始调用对应的Handler
处理业务逻辑,执行完成之后返回一个ModelAndView
。 -
这时候交给我们的
ViewResolver
,通过视图名称查找对应的视图,然后返回。 -
最后,渲染视图,返回渲染后的视图,响应给客户端。
web.xml配置
使用SpringMVC
不需要我们写Servlet
,但SpringMVC
是封装了Servlet
,提供 DispatcherServlet
来帮我们处理的。所以需要在 web.xml
配置 DispatcherServlet
。
可以看出 DispatcherServlet
,映射的url
是 /
,所以所有的请求都会被它拦截,再处理给我们。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 加载SpringMVC配置文件 -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 启动就加载这个Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
//省略其他配置...
</web-app>
SpringMVC工作机制
在容器初始化时会建立所有url
和controller
的对应关系,保存到Map<url,controller>
中。
tomcat
启动时会通知spring
初始化容器(加载bean
的定义信息和初始化所有单例bean
),然后springmvc
会遍历容器中的bean
,获取每一个controller
中的所有方法访问的url
,然后将url
和Controller
保存到一个Map
中;
这样就可以根据request
快速定位到Controller
。
初始化
我们知道,Servlet
初始化时,Servlet
的 init()
方法会被调用。Tomcat
初始化servlet
时,会来调用我们DispatcherServlet
的init()
方法,
我们进入 DispatcherServlet
中,发现并没有该方法,那么肯定在它继承的父类上。DispatcherServlet
继承于 FrameworkServlet
,结果还是没找到,继续找它的父类 HttpServletBean
。
HttpServletBean
终于找到了,HttpServletBean
继承于 HttpServlet
,我们来看下这个 init()
方法。
@Override
public final void init() throws ServletException {
//获取配置web.xml中的参数
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
//设置配置相关代码
.........
}
//重点:一个空方法,子类FrameworkServlet,重写了它,模板模式
initServletBean();
}
FrameworkServlet
initServletBean()
方法,就是一个初始化方法内主要是调用了 initWebApplicationContext()
初始化WebApplicationContext
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
//重点:初始化WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
//一个空方法,可以提供给以后的子类复写,做一些初始化的事情,暂时没有被复写
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
//省略无关代码...
}
而WebApplicationContext
继承于 ApplicationContext
,所以它是一个IoC
容器。
这就相当于初始化了FrameworkServlet
的属性WebApplicationContext
,而子类DispatcherServlet
继承了FrameworkServlet
,相当于DispatcherServlet
中有一个Spring
的容器,DispatcherServlet
收到请求后要根据请求的这一部分路径去找到Controller
里面对应的方法,而Controller
是Bean
对象,他就会到自己的Spring
容器去寻找Controller
的Bean
用于管理 Web 应用程序中的 bean
。
下面分析 initWebApplicationContext()
方法。
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//有参数构造方法,传入webApplicationContext对象,就会进入该判断
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
//还没初始化过,容器的refresh()还没有调用
if (!cwac.isActive()) {
//设置父容器
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//获取ServletContext,之前通过setAttribute设置到了ServletContext中,现在通过getAttribute获取到
wac = findWebApplicationContext();
}
if (wac == null) {
//创建WebApplicationContext,设置环境environment、父容器,本地资源文件
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
//刷新,也是模板模式,空方法,让子类重写进行逻辑处理,而子类DispatcherServlet重写了它
onRefresh(wac);
}
}
//用setAttribute(),将容器设置到ServletContext中
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
//WebApplicationContext
public interface WebApplicationContext extends ApplicationContext {
//...
}
FrameworkServlet
类的职责是将 Spring
容器和 Servlet
容器关联起来的功能。
这个方法,除了初始化WebApplicationContext
外,还调用了一个 onRefresh()
方法,又是模板模式,空方法,让子类复写进行逻辑处理,例如子类DispatcherServlet
重写了它
接来下,我们看子类 DispatcherServlet
复写的 onRefresh
()方法。
DispatcherServlet
而对于 DispatcherServlet
来说,它初始化方法是 onRefresh
()。
onRefresh()
方法,调用 initStrategies()
方法,进行各种组件的初始化工作。
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
//解析请求
initMultipartResolver(context);
//国际化
initLocaleResolver(context);
//主题
initThemeResolver(context);
//初始化HandlerMappings,Controller的方法和url映射关系
initHandlerMappings(context);
//初始化适配器,多样写法Controller的适配处理,实现最后返回都是ModelAndView
initHandlerAdapters(context);
//初始化异常处理器
initHandlerExceptionResolvers(context);
//初始化视图转发
initRequestToViewNameTranslator(context);
//初始化视图解析器,将ModelAndView保存的视图信息,转换为一个视图,输出数据
initViewResolvers(context);
//初始化映射处理器
initFlashMapManager(context);
}
initHandlerMappings 初始化处理器映射
//处理器映射集合
@Nullable
private List<HandlerMapping> handlerMappings;
//一个开关,标识是否获取所有的处理器映射,如果为false,则搜寻指定名为的 handlerMapping 的 Bean实例
private boolean detectAllHandlerMappings = true;
//指定的Bean的名称
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
private void initHandlerMappings(ApplicationContext context) {
//清空集合
this.handlerMappings = null;
//一个开关,默认为true,设置为false,才走else的逻辑
if (this.detectAllHandlerMappings) {
//重点:在容器中找到所有HandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
//找到了,进行排序,保证顺序
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
//指定搜寻指定名为 handlerMapping 的 HandlerMapping 实例
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
//也找不到映射关系,设置一个默认的
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
//配置文件名
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
//从配置文件中获取配置的组件,其他组件找不到时,也是调用这个方法进行默认配置
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
//...
}
}
如果找不到任何一个映射关系,会通过 getDefaultStrategies 方法,从配置文件中获取默认配置。其他组件找不到时,也是调用这个方法进行默认配置。
配置文件名:DispatcherServlet.properties。会加入默认的映射关系类 BeanNameUrlHandlerMapping 、 RequestMappingHandlerMapping。
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
HandlerAdapter 处理器适配器
HandlerAdapter 的初始化逻辑和上面的 HandlerMapping 基本一样。从容器中搜寻所有 HandlerAdapter 的实例。 如果找不到,则从配置文件中获取默认 的 HandlerAdapter。
//适配器集合
@Nullable
private List<HandlerAdapter> handlerAdapters;
//和上面HandlerMapping一样,一个开关,是否搜寻容器中所有的HandlerAdapter,如果为false,则搜寻指定名为 handlerAdapter 的Bean
private boolean detectAllHandlerAdapters = true;
//指定的HandlerAdapter实例
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
private void initHandlerAdapters(ApplicationContext context) {
//清空集合
this.handlerAdapters = null;
//也是一个开关,默认true,搜寻容器中所有的HandlerAdapter
if (this.detectAllHandlerAdapters) {
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
//找到了,进行排序,保证HandlerAdapter是有序的
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
//指定找名为 handlerAdapter 的HandlerAdapter
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
//没有找一个HandlerAdapter,从配置文件中获取默认的HandlerAdapter
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
HandlerExceptionResolver 异常处理器
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
//开关,是否梭巡所有的异常处理器,设置为false,就会找下面名为 handlerExceptionResolver 的Bean实例
private boolean detectAllHandlerExceptionResolvers = true;
//指定名为 handlerExceptionResolver 的实例
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
private void initHandlerExceptionResolvers(ApplicationContext context) {
//清空集合
this.handlerExceptionResolvers = null;
//开关,默认true
if (this.detectAllHandlerExceptionResolvers) {
//搜寻所有的异常处理器
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
//搜寻到了
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
//排序
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, no HandlerExceptionResolver is fine too.
}
}
//一个异常处理器都没有,从配置文件中获取默认的
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
ViewResolver 视图解析器
视图解析器和上面的解析器逻辑一样,先有开关决定是搜寻容器中所有的,还是搜寻指定名称的。
//视图解析器集合
@Nullable
private List<ViewResolver> viewResolvers;
//开关
private boolean detectAllViewResolvers = true;
//指定名称
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
private void initViewResolvers(ApplicationContext context) {
//清空集合
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
//搜寻所有视图解析器
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
//排序
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
try {
//搜寻指定名为 viewResolver 的视图解析器Bean
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default ViewResolver later.
}
}
//没有找到任何一个视图解析器,从配置文件中读取
if (this.viewResolvers == null) {
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
总结3个Servlet类的作用和职责
HttpServletBean
主要做一些初始化工作,解析 web.xml
中配置的参数到Servlet
上,比如init-param
中配置的参数。提供 initServletBean()
模板方法,给子类 FrameworkServlet
实现。
FrameworkServlet
将Servlet
和SpringIoC
容器关联。主要是初始化其中的 WebApplicationContext
,它代表SpringMVC
的上下文。
提供了 onRefresh()
模板方法,给子类 DispatcherServlet
实现,作为初始化入口方法。
DispatcherServlet
最后的子类,作为前端控制器,初始化各种组件,比如请求映射、视图解析、异常处理、请求处理等。
请求流程分析
当请求进入时,我们都知道会调用Servlet
的 service()
方法,我们试着去 DispatchServlet
中搜索,发现没有。去到父类 FrameworkServlet
找到了,FrameworkServlet
在service()
中区分成对应的回调方法调用 processRequest()
方法进行处理请求,而processRequest()
方法里面又调用了doService()
它是一个抽象方法,强制让子类进行复写。所以最终子类 DispatcherServlet
肯定会复写 doService()
方法。
DispatcherServlet doService()
doService()
方法中,主要的组件分发处理逻辑在 doDispatch()
方法中
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
........
try {
//重点:主要的组件分发处理逻辑在 doDispatch() 方法
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
doDispatch() 分发请求给各个组件处理
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);
//重点:找到本次请求的处理器以及拦截器,
mappedHandler = getHandler(processedRequest);
//找不到处理器处理,响应404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//重点:找到本次请求中,处理器的适配器
//获取处理器的适配器,因为有很多种处理器的实现方式,例如直接是Servlet作为处理器、实现Controller接口、使用Controller注解等,每个接口方法的返回值各式各样,所以这里使用了适配器模式,让适配器对处理器的返回值统一输出为ModelAndView。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
.......
//重点:处理前,责任链模式 回调拦截器的 preHandle() 方法,如果拦截了,则不继续往下走了
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//随后,就调用适配器的 handle() 方法,进行适配,执行真正的handle业务代码,让适配器将处理器的结果转换成统一的ModelAndView。处理完后,也代表请求进过Controller处理完毕。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果找不到默认的视图,则设置默认的视图
applyDefaultViewName(processedRequest, mv);
//重点:处理完成,遍历调用处理器执行链中的拦截器的 postHandle() 后置处理方法,代表请求以被处理,但视图还未渲染
mappedHandler.applyPostHandle(processedRequest, response, mv);
//.....视图创建和渲染过程
}
}
}
getHandler() 搜寻本次请求的处理器对象
责任链模式,遍历handlerMappings
集合,找到处理器和拦截器,会调用到getHandler()
方法。最后将处理器和拦截器都封装到 HandlerExecutionChain
这个处理器执行链对象中。
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
getHandlerAdapter() 获取处理器对应的适配器
遍历调用适配器集合,调用supports()
方法,询问每个适配器,是否支持当前的处理器。
如果返回true
,则代表找到了,停止遍历,返回适配器。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
//责任链模式,遍历调用适配器集合,调用supports()方法,询问每个适配器,是否支持当前的处理器
//如果返回true,则代表找到了,停止遍历,返回适配器
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");
}
拦截器前置通知
遍历拦截器链,调用它的 preHandle()
方法,通知拦截器进行请求处理前的拦截和附加处理。
如果有一个拦截器返回false
,代表拦截,则处理流程被中断,就是拦截了。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//遍历拦截器
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//执行拦截器preHandle方法
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
拦截器后置通知
逻辑还是遍历拦截器链,调用拦截器的 postHandle()
方法。
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
//遍历拦截器
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
- 初始化时
DispatchServlet
初始化,onRefresh
被调用,初始化处理器映射HandlerMapping
、HandlerAdapter
适配器、 异常处理器、 视图解析器 等一系列组件。
- 请求到达时
DispatchServlet
的doService()
被调用,根据请求的Url
查找对应的处理器,包含我们的Controller
和拦截器。- 根据处理器,找到对应的
HandlerAdapter
适配器,因为处理器的形式有很多,例如Servlet
作为处理器、实现Controller
接口,使用@Controller
注解等,返回值都不一,就要使用适配器将结果都适配为ModelAndView
。 - 执行适配器的处理方法前,先回调拦截器的前处理方法,如果拦截了,就不继续流程了。如果不拦截,则继续走,调用适配器的处理方法,在处理方法中,会调用处理器进行处理,就调用到我们的
Controller
。执行完后,再回调拦截器的后处理回调方法。 - 获取到
ModelAndView
后,交给视图解析器ViewResolver
,进行解析视图名称为具体视图实例后,再进行视图和数据的渲染返回给客户端,并回调拦截器视图渲染完后的回调方法。
请求到来时,从DispatchServlet
前端控制器开始,通过url
查找处理器,查找处理器对应的适配器,执行适配器的处理方法,返回ModelAndView
。视图处理器解析ModelAndView
,生成对应的视图对象,渲染视图和数据,并返回给客户端。