目录
预备
自研框架MVC的实现
MVC架构草图:
大致流程
实现思路
自定义注解
JavaBean
请求的拦截-建立DispatcherServlet
责任链处理请求
RequestProcessor矩阵
Render矩阵
-
预备
- 在DispatcherServlet:
- 解析请求路径和请求方法
- 依赖容器,建立并维护Controller方法与请求的映射
- 用合适的Controller方法去处理特定的请求
- 参照SpringMVC,仅通过DispatcherServlet进行请求派发这样可以让系统模块更加明确,该类的任务有:
- 拦截全部请求
- 解析请求
- 派发给对应的Controller里面进行处理
- 通过下面的注解可以拦截到全部请求
- 由于给DispatcherServlet标记了@WebServlet("/"),所以在tomcat启动之后会将DispatcherServlet给加载进来
- 因为设置了/匹配所有的的url-pattern,而且在tomcat插件中的设置了项目的根路径,<path>/${project.artifactId}</path>可以获取项目的名字,这样设置之后以项目名为根路径的请求都会经由DispatcherServlet来处理,里面的service方法就是用来处理请求的
- 相关的请求就会交给DispatcherServlet来处理,在DispatcherServlet加载到tomcat里面之后,在首次接收外部请求的时候,会调用里面init方法来完成自身的初始化,初始化之后调用service来处理相关的请求
- 后续的请求再到来时不会再执行初始化方法,直接调用service方法来处理请求
- HttpServletRequest里面包含了请求路径和请求方法以及请求里面的业务参数
- 通过类似简单工厂方法的模式解析请求方法和请求路径,按照请求路径和请求方法转发到对应的controller方法处理
- 在实际的使用中可以选择将返回的数据转换为json格式返回给前端,或者也可以生成相关的页面视图返回给前端去做渲染
- 下面的会对jsp请求也会进行拦截,如果我们在页面中转发到jsp,就依然会被拦截到这个类里
- 原因在tomcat的web.xml中,反斜杠是Servlet中特殊的匹配模式,优先级最低,比*.jsp优先级低,但是反斜杠星号属于路径匹配,优先级比*.jsp高
-
自研框架MVC的实现
-
MVC架构草图:
-
大致流程
- 获取http请求和需要回发的http响应对象,之后将他们委托给RequestProcessorChain处理
- 我们只处理get和post方法的请求,RequestProcessorChain参照的是责任链模式的后置处理器的处理逻辑,里面保存了处理RequestProcessor接口的多个不同的实现类,之所以会有多个不同的实现类对应为DispatcherServlet是项目里面所有请求的唯一入口
- DispatcherServlet[ 调度Servlet ]的作用是将请求分发到不同的处理器
- 这些请求里即会有获取jsp页面的请求,也会有获取静态资源的请求、直接获取json数据的请求等,针对不同的请求会使用不同的RequestProcessor来处理
- Spring MVC框架像许多其他MVC框架一样,以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)
- 简要分析执行流程
- 1-DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心
- 用户发出请求,DispatcherServlet接收请求并拦截请求
- 假设请求的url为:http://localhost:8080/SpringMVC/hello
- 如上url拆分成三部分:
- http://localhost:8080服务器域名
- SpringMVC部署在服务器上的web站点
- hello表示控制器
- 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
- 2-HandlerMapping为处理器映射;DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler
- 3-HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello
- 4-HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等
- 5-HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
- 6-Handler让具体的Controller执行
- 7-Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
- 8-HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
- 9-DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名
- 10-视图解析器将解析的逻辑视图名传给DispatcherServlet
- 11-DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图
- 12-最终视图呈现给用户
-
实现思路
- 自研框架实现思路定义DispatcherServlet分发器
- 创建责任链对象实例
- 通过责任链模式来依次调用请求处理对请求进行处理
- 对处理结果进行渲染
-
自定义注解
- @RequestMapping 标识controller的方法和请求路径和请求方法的映射问题
- @RequestParam 请求方法参数名
- @ResponseBody 用于标记自动对返回值进行json处理
-
JavaBean
- ControllerMethod 待执行的Controller及其方法实例和参数的映射
- ModelAndView 存储处理完后的结果数据以及显示该数据的视图
- RequestMethod 框架目前支持的请求方法
- RequestPathInfo 储存http请求路径和请求方法
-
请求的拦截-建立DispatcherServlet
- 初始化容器
- 初始化请求处理器责任链
- 通过责任链模式来依次调用请求处理器对请求进行处理
- 对处理结果进行渲染
- init方法
- 对常驻变量进行初始化
- servlet是程序执行的入口:对容器进行初始化并将相关的bean加载进来,同时完成AOP相关逻辑的织入,以及相关的IoC依赖注入等操作
- 因为后面是采用责任链模式来实现RequestProcessor矩阵的,要将对应的处理器添加到处理器列表中
- 将RequestProcessor矩阵按序添加到缓存列表里
- 之所以按照图示的顺序进行添加,是因为我们的请求经过编码和路径的处理之后才能进行后续的处理
- 将ControllerRequestProcessor放在最后是因为它的处理会比较耗时,需要将请求和controller的方法实例进行匹配
- service方法
- 首先创建责任链对象实例
- 然后通过责任链模式来依次调用请求处理器对请求进行处理
- 通过迭代器遍历注册的请求处理器实现类列表
- 直到某个请求处理器执行后返回false为止
- 期间如果出现异常,则交由内部异常渲染器处理
- 最后对处理结果进行渲染
- 如果请求处理器实现类均未选择合适的渲染器,则使用默认的
- 调用渲染器的render方法对结果进行渲染
-
责任链处理请求
- 以责任链的模式执行注册的请求处理器
- 委派给特定的Render实例对处理后的结果进行渲染
-
RequestProcessor矩阵
- PreRequestProcessor处理器(请求预处理器):主要负责对请求的编码以及对路径做一些前置处理
- 剩余的处理器都会去解析请求,以看看请求是否由该处理器去处理的
- StaticResourceRequestProcessor处理器(静态资源处理器):对静态资源请求
- 利用的tomcat默认请求派发器RequestDispatcher处理
- JspRequestProcessor处理器(JSP处理器):对jsp页面的访问请求进行处理(不仅过controller直接访问页面的请求)
- 利用的tomcat的jspServlet处理
- ControllerRequestProcessor处理器(Controller处理器):将请求派发到对应的controller方法里面进行处理
- 针对特定请求,选择匹配的Controller方法进行处理
- 解析出请求里的参数及其对应的值,并赋值给Controller方法的参数
- 选择合适的Render,为后续请求处理结果的渲染做准备
- 建立Controller方法与请求的映射关系
- 请求中包含的信息有路径和请求参数,所以需要根据这些信息找到对应的Controller方法
- 利用RequestPathInfo存储请求的信息,ControllerMethod存储Controller以及方法的信息
- 建立的映射关系就是RequestPathInfo与ControllerMethod的,这样就可以根据请求定位到对应的方法
- 然后利用ConverterUtil给需要执行的方法参数赋值
- 最后利用反射执行获取执行的结果,根据结果设置结果渲染器
-
Render矩阵
- 渲染,处理了相关的请求之后,需要将结果以不同的形式给展现出来,并且处理的过程中可能会出现各种各样的异常,也需要去做体现
- Render负责对结果进行包装并展现
- 当处理器处理完之后就会调用特定的实现了Render接口的实现类,对处理结果进行展现
- DefaultResultRender(默认结果渲染器):当请求处理成功后,用户只需要返回一个成功的状态码
- 如果请求处理器实现类均未选择合适的渲染器,则使用默认的结果渲染器
- 主要将处理的结果状态码返回,默认为200
- JsonResultRender(Json结果渲染器):用户发送的请求是想要获取json格式的返回结果
- 当方法上面使用@ResponseBody 注解时,利用Gson将结果转换成Json数据返回
- ViewResultRender(视图解析器):将逻辑视图转换成用户可以看到的物理视图,类似于ModelAndView对象
- 视图解析器则根据返回结果的不同,而进行跳转
- 如果是String数据,则创建一个ModelAndView对象,并将数据加入到视图地址
- 如果是ModelAndView,则会解析其中的视图地址和数据
- 针对其他情况,则直接抛出异常
- InternalErrorResultRender(异常结果渲染器):对异常的处理
- 以责任链的模式处理请求,期间如果出现异常,则交由内部异常渲染器处理
- 设置状态码500和异常信息
- ResourceNotFoundResultRende(找不到路径渲染器):资源无法找到的异常
- 在根据请求路径转发到Controller时,找不到对应的对象或者方法,则使用该渲染器
- 返回404和请求的路径及方法
- 测试成功