西安 做网站 499,网站 建设 问题,网站建设公司华网天下公司,百度网站建设公司前面我们学习了 Spring 最核心的 IoC 与 AOP 模块#xff08;读书笔记-《Spring技术内幕》#xff08;一#xff09;IoC容器的实现、读书笔记-《Spring技术内幕》#xff08;二#xff09;AOP的实现#xff09;#xff0c;接下来继续学习 MVC#xff0c;其同样也是经典…前面我们学习了 Spring 最核心的 IoC 与 AOP 模块读书笔记-《Spring技术内幕》一IoC容器的实现、读书笔记-《Spring技术内幕》二AOP的实现接下来继续学习 MVC其同样也是经典。
我们依旧按照从浅到深的方式来学习先从程序员的视角看看其简化了哪些工作帮我们做了什么再到具体的设计与实现。 01
MVC 概述 在之前 IoC 的笔记中有这样一张图 这里依然可以复用从程序员的视角来看Spring MVC 带来的最直观的好处是我们不需要再去写繁琐冗余的 Servlet而是改写 Controller。
拉长时间线来看JavaWeb 的技术发展历程大致如下 总结一下就是初期使用的技术在业务的发展中逐渐暴露出局限性于是有了分层思想按照数据维度分层的 MVC 是最经典的分层模式Spring MVC 就是 MVC 的实现之一。
除了 MVC还有按照业务维度分层的 DDD不过后者用得比较少其比较适合复杂系统并且需要所有人员产品、研发、测试都有较高水准的业务理解。 02
Spring MVC 概述 了解了 MVC 后我们可以很快明白 Spring MVC 的重点工作。Model 层的 Bean 初始化Controller 层的请求处理以及 View 层的视图呈现。具体步骤就是下面三步 初始化通过 Bean 定义在 IoC 容器初始化时建立起 Controller 与 HTTP 请求的映射关系。 处理请求MVC 框架接收到 HTTP 请求DispatcherServlet 根据 URL 查询到具体的 ControllerController 完成请求并生成 ModelAndView 对象。 呈现视图视图对象通过 render 方法完成视图的呈现。
接下来我们就可以展开步骤来详细看看其实现了。 03
Spring MVC 设计与实现 1.初始化
我们以 Tomcat 的 web.xml 文件为例
servletservlet-namesample/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-classload-on-startup2/load-on-startup
/servletservlet-mappingservlet-namesample/servlet-nameurl-pattern/*/url-pattern
/servlet-mappingcontext-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/applicationContext.xml/param-value
/context-paramlistenerlistener-classorg.springframework.web.context.ContextLoaderListener/listener-class
/listener
可以看到其定义了一个叫 sample 的 servlet全限定类名正是 DispatcherServlet且其将处理所有请求。而后这里还有一个 Bean 定义的配置文件是 WEB-IN 目录下的 applicationContext.xml。最后有个监听器 ContextLoaderListener其将负责完成 IoC 容器在 Web 环境中的启动。
从代码上来看Web 容器中启动 Spring 应用程序的过程如下 ContextLoaderListener.contextInitialized() 初始化根上下文其中调用父类 ContextLoader 的方法 ContextLoader.initWebApplicationContext() 初始化 Web 应用上下文其中有挺多异常校验和日志打印 ContextLoader.loadParentContext() 加载双亲上下文 XmlWebApplicationContext.createWebApplicationContext() 创建 Web 应用上下文 XmlWebApplication.refresh() 刷新。这里前面讲 IoC 的时候也讲到了refresh 方法可以视作整个容器的初始化方法。 在根上下文初始化好后就可以关注 DispatcherServlet 了。从前面的概述也看得出来其是 Spring MVC 的核心。DispatcherServlet 的初始化和处理过程大致如下 上面时序图中从右到左依次是继承关系我们来详细描述下上半边 HttpServletBean.init() 基类的初始化首先会获取 Servlet 的初始化参数对 Bean 属性进行配置也就是上面我们举例的配置文件里的 Bean然后调用子类的方法 FrameworkServlet.initServletBean() 初始化 Servlet Bean FrameworkServlet.initWebApplicationContext() 从 ServletContext 中获取根上下文并设置为当前 MVC 上下文的双亲上下文再把当前上下文设置到 ServletContext 中去根上下文也就是上面提到的 ContextLoader 设置到 ServletContext 中去的; 上面的 FrameworkServlet.initWebApplicationContext() 中会调用自己的 createWebApplicationContext() 里面就包含了 refresh(); DispatcherServlet.onRefresh(); DispatcherServlet.initStrategies() 启动框架的初始化代码很简洁依次初始化 multipartResolver、localeResolver、themeResolver、handlerMappings、handlerAdapters、handlerExceptionResolvers、requestToViewNameTranslator、viewResolvers; 以 initHandlerMappings() 为例将设置所有的 handlerMapping Bean这些 Bean 可能在当前 DispatcherServlet 的 IoC 容器中也可能在双亲上下文中。如果都没有找到则去 DispatcherServlet.properties 中找默认值。 2.处理请求
前面初始化已完成接下来就关注上面那张图的下半边也就是 DispatcherServlet 的 doDispatch() 了。
注意 HandlerMapping 有很多实现比如通过 Bean 名称的、通过类名称的我们以SimpleUrlHandlerMapping 为例先看下关键的数据结构
// 1.基类定义了方法 getHandler返回一个 Chain
public interface HandlerMapping {HandlerExecutionChain getHandler(HttpServletRequest req) throws Exception;……
}// 2.Chain 里持有了 handler也就是我们编写的 Controller
// 还有个拦截器链对 handler 进行功能增强
public class HandlerExecutionChain {private final Object handler;private HandlerInterceptor[] interceptors;private ListHandlerInterceptor interceptorList;……
}// 3.关键的成员变量key 是 urlvalue 是对应的处理 handler
// 它的赋值是在 SimpleUrlHandlerMapping.initApplicationContext() - AbstractUrlHandlerMapping.registerHandler() 里
// 它的使用是在 AbstractHandlerMapping.getHandler() - AbstractUrlHandlerMapping.getHandlerInternal() 里
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping {private final MapString, Object handlerMap new LinkedHashMapString, Object();……
}
再看看 doDispatch() 的详细时序图 可以看到doDispatch() 完成了模型、控制器、视图的耦合处理从根据请求得到对应的 handler到调用 handler 的拦截器到调用适配器的 handle()最后到 ModelAndView 的呈现。 3.呈现视图
对于最后的视图呈现除了当时常见的 JSP 视图还有 Excel 视图、PDF 视图等等。不过现在都不涉及了主流的应用都通过前后端分离的方式将数据的展示交给前端开发处理。
关于视图呈现我们以 JSP 视图为例过程如下 DispatcherServlet.render() 里面有两种情况一种是在 ModelAndView 中设置了 View 的名称需要调用 resolveViewName 方法获取 View还有一种情况是 ModelAndView 里已经有 View 了则直接使用注意这里说的 render 方法是 DispatcherServlet 的上面时序图里说的 render 方法是 View 的 DispatcherServlet.resolveViewName() 调用 ViewResolver.resolveViewName()后者会到上下文中通过名称把 View 的 Bean 对象获取到 AbstractView.render() 这里是基类的方法把所有 Model 进行整合放在一个 HashMap 里然后继续往下调用 InternalResourceView.renderMergedOutputModel() 这里接着会往 AbstractView 调用。不过最终就是 InternalResourceView 完成了数据到页面的输出以及资源的重定向处理 AbstractView.exposeModelAsRequestAttributes() 把 ModelAndView 中的模型数据和请求数据都放到 HttpServletRequest 的属性中去这样程序员就可以愉快的使用了。 原文链接读书笔记-《Spring技术内幕》三MVC与Web环境
原创不易点个关注不迷路哟谢谢
文章推荐
如何提高核心竞争力读书笔记-《当下的力量》读书笔记-《写给大家看的设计书》赛博朋克2077玩后感程序员工作中常见问题你遇到过几个如何设计离线跑批系统读书笔记-《人人都是产品经理》