1 什么叫MVC
mvc是一种架构模式,视图层只去管理页面,model层只去管理业务逻辑,控制层就像是一个媒婆,来关联view层和model,它负责页面的跳转和调用model层。
常见的MVC框架:
- Struts
- SpringMVC
- ZF
- .NET
2 SpringMVC
2.1 初识
SpringMVC一定程度上是为了取代原生的servlet,加上天然被SpringIOC容器支持,所以广受使用。
SpringMVC和Stuts的基本区别是:
-
SringMVC的底层是基于Servlet的
-
Struts的底层是基于过滤器
2.2 核心组件
组件名 | 说明 |
---|---|
DisPatcherSrtvlet | SpringMVC的入口,作用就是对请求分流/分配,底层是servlet |
HandlerMapping | 处理器映射器,检查请求是否合法(有没有对应的handler,控制器去处理),默认使用的是RequestMappingHandlerMapping |
HandlerAdapter | 处理器适配器,根据适配器设计模式去匹配接口,默认是RequestMappingHandlerAdapter |
Handler | 具体去处理请求,然后根据业务逻辑作出相应 |
ViewResolver | 将数据和指定的模版引擎结合起来 |
2.3 DisPatcherServlet源码分析
前端控制器/中央处理器,它的本质其实一个servlet,用户所有的请求会被它拦截到以后进行对应的分发。其中最核心的方法就是里面的doService方法,下面是该方法的源码。
源码分析:
在FrameWorkServlet中,Spring重写了Servlet处理请求和响应的方法
......
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 这里将请求方法映射在在Map集合中,查找该请求的请求方法
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
// 如果找不到该请求方法,就直接拦截该请求
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
// Spring加工的请求
processRequest(request, response);
}
else {
super.service(request, response);
}
}
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Spring加工的请求
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Spring加工的请求
processRequest(request, response);
}
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Spring加工的请求
processRequest(request, response);
}
......
Spring把所有的请求响应进行了加工
processRequest()
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
......
// 在加工的方法中,最终调用了doService方法,而这个方法被DispatcherServlet重写了
try {
doService(request, response);
}
......
}
DispatcherServlet的doService方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
Map<String, Object> attributesSnapshot = null;
// 判断请求的属性是否有javax.servlet.include.request_uri
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
// 设置了web应用上下文
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
......
// 在最后调用了doDispatch()方法,在这个方法中控制了请求的转发
try {
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);
// 第二步、通过请求使用对应的hadler处理器获取handler
mappedHandler = getHandler(processedRequest);
// 如果handler为空,说明没有找到对应的controller,返回404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 第三步、 获取处理器适配器,通过mappedHandler执行链获得对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 判断last-modified
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);
}
// 如果lastModified没有发生变化,则直接返回,告诉浏览器使用缓冲资源
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 前拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 第四步,处理controller层,获得返回的ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 视图解析器
applyDefaultViewName(processedRequest, mv);
// 后拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
......
}
2.4 工作流程
当浏览器发送一个请求后,将都会由
DispatcherServlet
来接收,通过浏览器发起的请求
,通过HandlerMapping
来寻找对应的Handler,如果存在该Handler则会返回给DispatcherServlet
对应的执行链,中央处理器将执行链发给HandlerAdatper
来执行对应的执行链,对应的Handler
执行完后会返回一个ModelAndView对象,DispatcherServlet
会将对应的ModleAndView对象传给配置好的ViewResolver
视图解析器去解析,最终返回一个页面。