springmvc小计
2020-06-18 本文已影响0人
可靠的千秋
近日在复习SpringMVC,故整理一下笔记
SpringMVC是在Spring框架内置的MVC的实现,其本质是对Servlet的一个封装。
MVC(Model-View-Controller,模型-视图-控制器)指把页面、后台的交付分成3层来组成,是一种解决页面代码(视图代码)和后台代码分离的设计思想。
SpringMVC原理
1,在web.xml中配置过ContextLoaderListener监听器,监听容器的启动
2,监听器监听容器启动,加载配置文件,初始化对象存在容器中
3,用户发起请求,到HttpServlet,调doPost/doGet/doPut/doDelete,调用DispatcherServlet的doDispatch方法,进行具体请求的处理
4,处理完成,返回一个ModelAndView,视图解析器进行渲染,返回前端。
核心方法doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//handler执行链
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);
// Determine handler for the current request.
//根据请求,找到能处理当前请求的执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//404
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//获得处理请求适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) { //拦截器
return;
}
// Actually invoke the handler. 实际处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//结构视图对象处理
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv); //拦截器
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//跳转页面渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
这边直接贴出代码,其核心是**mv = ha.handle(processedRequest, response, mappedHandler.getHandler());**这行来执行真正的请求。
1,实际上里面是通过找到Method的对象,进行的反射调用。那是怎么找到Method的呢,是因为HandlerAdapter
HandlerAdapter
我们来看HandlerAdapter,他有好几个实现类
![下载](https://note.youdao.com/yws/res/5751/F2E4DCC6847D4F419445692639EA797F)
AbstractHandlerMethodAdapter的handle调用handleInternal,然后调用RequestMappingHandlerAdapter的invokeHandlerMethod方法->invocableMethod.invokeAndHandle(webRequest, mavContainer) -> invokeForRequest -> doInvoke -> getBridgedMethod().invoke(getBean(), args) 进行具体执行,其实就是解析参数,进行反射调用。
2,我们再来看getHandler(processedRequest);获得具体的处理器映射器
@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;
}
其执行的是getHandler,循环调用mapping.getHandler(request);而getHandler内部调用getHandlerExecutionChain(handler, request);做一个url的匹配,返回一个HandlerExecutionChain执行链
我们来看mapping,他是一个HandlerMapping类型的集合,HandlerMapping的核心实现RequestMappingHandlerMapping类,用来映射请求映射的一个关系对象,它的getMappingForMethod方法在bean对象启动时加载,返回一个RequestMappingInfo对象,缓存方法请求的信息,也就是项目启动时,会将方法上的@RequestMapping会被转换为RequestMappingInfo对象,isHandler方法用于过滤是否是被Controller和RequestMapping修饰
项目启动之后,Spring可以获取到容器中的所有Bean对象。而RequestMappingHandlerMapping是@RequestMapping标签的处理器映射器。
而为什么mapping会有数据呢,他其实是DispatcherServlet九大组件之一,在Servlet启动的时候,会调用init,然后向下执行onRefresh->initStrategies(),从ApplicationContext里初始化9大组件HandlerAdapters也是在这时候初始化的