springMVC分析-1
MVC
作为一个MVC框架,必须回答一下几个问题
- 请求映射到控制器
- 请求数据进行绑定
- 视图渲染
而spring mvc是如何解决这几个问题的呢?
首先,从DispatcherServlet这个入口开始分析,DispatcherServlet继承于FrameworkServlet,而FrameworkServlet继承HttpServletBean,HttpServletBean又继承与HttpServlet,先从
HttpServletBean的init方法开始分析
@Override
public final void init() throws ServletException {//省略// Let subclasses do whatever initialization they like. initServletBean();//这是个空方法,可以给其子类进行重写}
再从其子类FrameworkServlet重写的initServletBean()方法
@Override
protected final void initServletBean() throws ServletException {//日志块省略try {//初始化springMvc的ApplicationContext、并查找是否有spring的ApplicationContext 并将其设置为root applicationContext ,初始化spring mvc的beanthis.webApplicationContext = initWebApplicationContext();//空方法,可扩展initFrameworkServlet();}//catch块,日志省略
}
继续分析DispatcherServlet init()方法
protected void initStrategies(ApplicationContext context) {//初始化处理mine为multipart/form-data的处理器initMultipartResolver(context);//初始化本地化处理器,默认是以用户的http请求的AcceptHeaderLocaleResolverinitLocaleResolver(context);//初始化主题处理器initThemeResolver(context);//初始化HandlerMappingsinitHandlerMappings(context);//初始化处理器适配器initHandlerAdapters(context);//处理异常处理器initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);//处理视图转换initViewResolvers(context);initFlashMapManager(context);
}
从上面代码可以看出来,DispatcherServlet会初始化一些处理器,再分析其处理请求的方法
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 {//判断是否是multipart/form-dataprocessedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 将请求映射到具体的处理器mappedHandler = getHandler(processedRequest);if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}对处理器进行适配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 (logger.isDebugEnabled()) {logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}拦截器处理if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 调用具体的控制器进行处理mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);拦截器处理mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}//处理异常、渲染视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}//省略
}
上述代码包括了请求到响应 spring做的过程。我们来细化分析一下。
首先我们来分析请求映射到逻辑处理器的过程
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {if (logger.isTraceEnabled()) {logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;
}
从这段代码看,其会遍历所有的HandlerMapping,然后获取一个HandlerExecutionChain执行对象,而入参是HttpServletRequest,意味着这个HandlerMapping可以根据http请求的所有信息获取到一个控制器。这是第一个扩展点,我们可以实现一个HandlerMapping来处理请求映射。再看HandlerExecutionChain这个类
public class HandlerExecutionChain {private final Object handler;private HandlerInterceptor[] interceptors;}
这个类最重要的两个属性,可以看出其对执行对象里面包含了两个部分,一个是控制器,另一个则是拦截器数组,这是第二个扩展点,我们可以实现HandlerInterceptor,在控制器处理前后进行一些操作。
我们来这个操作,其会获取一个控制器的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {for (HandlerAdapter ha : this.handlerAdapters) {if (logger.isTraceEnabled()) {logger.trace("Testing handler adapter [" + ha + "]");}if (ha.supports(handler)) {return ha;}}
}
从这个方法的执行,我们可以看出来其依旧是遍历handlerAdapters后返回第一个HandlerAdapter进行处理Handler,所以我们可以实现HandlerAdapter这个接口,自定义对Handler进行处理,这是第三个扩展点
继续玩下走,在processDispatchResult()方法中,先判断是否有exception,若有且不是ModelAndViewDefiningException,则交给HandlerExceptionResolver处理,HandlerExceptionResolver是个接口,可以看出这是第四个扩展点。继续往下走,到render()方法,
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine locale for request and apply it to the response.Locale locale = this.localeResolver.resolveLocale(request);response.setLocale(locale);View view;// 判断View是不是字符串if (mv.isReference()) {//交给ViewResolvers处理,将其转换成View对象view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);if (view == null) {throw new ServletException("Could not resolve view with name '" + mv.getViewName() +"' in servlet with name '" + getServletName() + "'");}}else {// No need to lookup: the ModelAndView object contains the actual View object.view = mv.getView();if (view == null) {throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +"View object in servlet with name '" + getServletName() + "'");}}// Delegate to the View object for rendering.if (logger.isDebugEnabled()) {logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");}//将数据渲染到视图中try {view.render(mv.getModelInternal(), request, response);}
}
至此springMVC从请求到响应的流程结束,可以看出springMVC玩的是开闭原则,对修改关闭,可扩展。这是个大体流程,下一篇文章将分析其细节化
转载于:https://www.cnblogs.com/myzhong2014/p/5301847.html
springMVC分析-1相关推荐
- springMVC分析-2
springMVC的请求映射 上一次分析了一下springMVC的大致流程,这次细分一下,对请求映射进行分析. 先从DispatcherServlet中的getHandler()方法分析 protec ...
- spring和springMVC配置文件中的扫描包如何配置
我的项目大概文件路径: 然后进入主题: spring的配置文件名称为applicationContext.xml springMVC的配置文件名称为dispatcherServlet-servlet. ...
- SSM框架学习文档以及SSM整合(附Github地址=含SSM学习时的实例代码)
SSM框架学习 软件架构: 基于流行SSM框架:Spring+SpringMVC+Mybatis 项目配置: 使用Maven进行项目jar导入 使用Git进行版本控制,并将每次编写的代码上传到Gi ...
- spring注解驱动开发-10 Servlet3.0
Spring AOP实现 前言 servlet3.0简介 ServletContainerInitializer shared libraries(共享库) / runtimes pluggabili ...
- 尚硅谷Spring注解开发学习笔记
文章目录 前言 1.课程安排 1.1.容器 1.2.扩展原理 1.3.Web 2.配置文件开发 2.1.导入Spring-context依赖包 2.2.编写Spring配置文件 2.3.编写Perso ...
- SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)
[SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...
- SpringMVC启动分析
以下分析基于JDK1.8 启动的第一步是执行监听器,这里web.xml中配置了一个监听器org.springframework.web.context.ContextLoaderListener 接下 ...
- SpringMVC学习(一)———— springmvc框架原理分析和简单入门程序
一.什么是springmvc? 我们知道三层架构的思想,并且如果你知道ssh的话,就会更加透彻的理解这个思想,struts2在web层,spring在中间控制,hibernate在dao层与数据库打交 ...
- SpringMVC之源码分析--ViewResolver(四)
概述 本章继续学习ViewResolver另一个实现类ContentNegotiatingViewResolver解析器,该类的主要作用是根据同一请求的某些策略,选择对应的View进行渲染.可以把Co ...
最新文章
- 看似简单但容易忽视的编程常识
- PHP06 PHP操作MySQL
- django升级问题
- 后台服务系统之搭建ZooKeeper注册中心
- 线程打印_线程知识回顾
- WebService开发中SoapException的用法
- linux之SQL语句简明教程---SUBSTRING
- 95-30-010-Channel-AbstractChannel
- 促销海报灵感素材,不卖出去都难
- android 如何快速检测到画面变化_电瓶修复—如何快速检测电池的好坏2
- android SDK安装以及环境变量配置(windows)
- JSP中文乱码问题终极解决方案(下)
- python import 搜索包路径的机制,以及添加自定义python包的方法
- 一篇文章带你搞定 create connection SQLException, url: jdbc:mysql://10.15.16.63:3306/restful, errorCode 1130
- 如何升级php到最新版本_如何将PHP升级到最新版本
- odi12配置mysql_Oracle数据库之Oracle ODI 12c之多表联合查询以及定时任务设置
- java、.net、IOS、Android自学编程学习视频与资料
- 如何与新同事共同成长?
- ESMTP协议与SMTP协议
- 【C++】关于char * tempbuffer = new char[100];