【Spring】SpringMVC DispatcherServlet 和 Controller的交互
1. MVC架构1.1 FrontController: DispatcherServletFrontController就是Spring提供的DispatcherServlet , 而不是Spring提供的@Controller,xml配置文件需要指定Tomcat启动时优先加载该Servlet映射路径写/,转发所有请求<servlet><ser...
1. MVC架构
1.1 FrontController: DispatcherServlet
FrontController
就是Spring提供的DispatcherServlet
, 而不是Spring提供的@Controller
,xml配置文件需要指定Tomcat启动时优先加载该Servlet映射路径写/
,转发所有请求
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--tomcat启动的时候, 优先加载这个Servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
DispatcherServlet
本质上是一个HttpServlet
追踪HttpServlet.service() 方法的调用链
-
FrameworkServlet
继承父类的HttpServlet.service
,Spring的拓展实现是processRequest
FrameworkServlet.processRequest
,==Spring会拦截所有类型的请求,包括HttpServlet里没有定义的,==继续追踪processRequest
的实现@Override protected void service(HttpServletRequest request, HttpServletResponse response) { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } }
-
FrameworkServlet.processRequest
组合了doService
逻辑protected final void processRequest(HttpServletRequest request, HttpServletResponse response) { try { doService(request, response); } // 留作后文研究 publishRequestHandledEvent(request, response, startTime, failureCause); } }
-
FrameworkServlet
的抽象方法doService
是留给子类必须实现的,也就是DispatcherServlet.doService()
protected abstract void doService(HttpServletRequest request, HttpServletResponse response);
/** * DispatcherServlet.doService() * */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) { // 省略数据准备 try { doDispatch(request, response); } }
追踪FrameworkServlet.doPost() / doGet() …
FrameworkServlet.doGet/doPost/..
无一例外使用processRequest的实现,也就是DispatcherServlet.doService
探究FrameworkServlet.service() 模板方法实现
-
super.service()
利用了模板设计模式,Spring 兼容了PATCH的实现,其他交给HttpServlet的模板service()
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } }
-
HttpServlet.service()
模板,无具体实现。由于FrameworkServlet.doGet/doPost..
都已经覆盖了HttpServlet的实现
,一个Get请求经过DispatcherServlet后,有以下过程FrameworkServlet.service()
->super.service()
->FrameworkServlet.doGet()
->
FrameworkServlet.processRequest()
->DispatcherServlet.doService
->
DispatcherServlet.doDispatch()
/** * super.service() 最总会调用到 HttpServlet 的模板方法 * */ protected void service(HttpServletRequest req, HttpServletResponse resp) { String method = req.getMethod(); if (method.equals(METHOD_GET)) { doGet(req, resp); } 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); } }
小结
DispatcherServlet
作为MVC架构中的前端控制器,也是常说的核心控制器, 通过HttpServlet.service()
的模板模式把请求 转发给Spring ,DispatcherServlet.doService() 后续解析
,
关于DispatcherServlet
的其他父类, 网上收集到的作用:
-
HttpServletBean,是FrameworkServlet的父类
主要做一些初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet标签的子标签init-param标签中配置的参数。
-
FrameworkServlet
将Servlet与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性
webApplicationContext
,这个属性代表SpringMVC上下文,它有个父类上下文ServletContext
,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。 -
DispatcherServlet (后文会提到)
初始化各个功能的实现类。比如异常处理、视图处理、请求映射处理等。
2. MVC交互流程
2.1 Controller: DispatcherServlet.doService()
追踪 DispatcherServlet.doDispatch()
doService() 内部调用的是 doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
HttpServletRequest processedRequest = request;
// Determine handler for the current request.(追踪)
HandlerExecutionChain mappedHandler = getHandler(processedRequest)
// Determine handler adapter for the current request.(追踪)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Actually invoke the handler.(追踪)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
追踪 DispatcherServlet.getHandler()
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
Handler 是根据 HandlerMapping 获取的,对应Controller的@RequestMapping
追踪 DispatcherServlet. getHandlerAdapter()
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
}
追踪 HandlerAdapter.handle()
ModelAndView handle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception;
在DispatcherServlet中找到ModelAndView 的返回值出处
追踪 HandlerAdapter 实现类 SimpleControllerHandlerAdapter
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
追踪 Controller 实现
public interface Controller {
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
最终找到了 Controller 返回MV的代码, 也印证了DispatcherServlet.doDispatcher 最终会返回 Controller 拼装而成的 ModelAndView
2.2 Model And View
不同的视图解析器决定如何处理解析 视图名,所以SpringMVC需要配置视图解析器
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
3. 总结
DispatcherServlet 会寻找 HandlerMapping 和 HandlerAdaptor, 解析视图的时候会用到 ViewResolver
如果手动集成SSM,SpringMVC需要手动注入这三个bean。值得一提的是,XML配置如果开启了注解支持,HandlerMapping 和 HandlerAdaptor也随之加载。具体可以见以下图
更多推荐
所有评论(0)