From c32dd7ead58ef98d2fae81db6be9ec58525b821a Mon Sep 17 00:00:00 2001 From: wu xiangkai Date: Thu, 17 Nov 2022 18:05:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A5=E5=B8=B8=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/Spring core/SpringMVC.md | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/spring/Spring core/SpringMVC.md b/spring/Spring core/SpringMVC.md index e1a6692..07dd8df 100644 --- a/spring/Spring core/SpringMVC.md +++ b/spring/Spring core/SpringMVC.md @@ -3,3 +3,58 @@ SpringMVC是一款基于Servlet API的web框架,并基于前端控制器的模式被设计。前端控制器有一个中央的控制器(DispatcherServlet),通过一个共享的算法来集中分发请求,请求实际是通过可配置的委托组件(@Controller类)来处理的。 > Spring Boot遵循不同的初始化流程。相较于hooking到servlet容器的生命周期中,Spring Boot使用Spring配置来启动其自身和内置servlet容器。filter和servlet声明在在spring配置中被找到并且被注入到容器中。 +## DispatcherServlet +### Context层次结构 +DispatcherServlet需要一个WebApplicationContext(ApplicationContext的拓展类,Spirng容器)来进行配置。WebApplicationContext拥有一个指向ServletContext和与ServletContext关联Servlet的链接。 +**同样的,也可以通过ServeltContext来获取关联的ApplicationContext,可以通过RequestContextUtils中的静态方法来获取ServletContext关联的ApplicationContext。** +#### WebApplicationContext的继承关系 +对大多数应用,含有一个WebApplicationContext就足够了。也可以存在一个Root WebApplicationContext在多个DispatcherServlet实例之间共享,同时DispatcherServlet实例也含有自己的WebApplicationContext。 +通常,被共享的root WebApplicationContext含有repository或service的bean对象,这些bean对象可以被多个DispatcherServlet实例的子WebApplicationContext共享。同时,子WebApplicationContext在继承root WebApplicationContext中bean对象的同时,还能对root WebApplicationContext中的bean对象进行覆盖。 +> #### WebApplicationContext继承机制 +> 只有当Servlet私有的子WebApplicationContext中没有找到bean对象时,才会从root WebApplicationContext中查找bean对象,此行为即是对root WebApplicationContext的继承 + +### Spring MVC中特殊的bean类型 +DispatcherServlet将处理请求和渲染返回的工作委托给特定的bean对象。Spring MVC中核心的bean类型如下。 +#### HandlerMapping +将请求映射到handler和一系列用于pre/post处理的拦截器。 +#### HandlerAdapter +HandlerAdapter主要是用于帮助DispatcherServlet调用request请求映射到的handler对象。 +通常,在调用含有注解的controller时需要对注解进行解析,而HandlerAdapter可以向DispatcherServlet隐藏这些细节,DispatcherServlet不必关心handler是如何被调用的。 +#### HandlerExceptionResolver +解析异常的策略,可能将异常映射到某个handler,或是映射到html error页面。 +#### ViewResolver +将handler返回的基于字符串的view名称映射到一个特定的view,并通过view来渲染返回的响应。 + +### Web MVC Config +在应用中可以定义上小节中包含的特殊类型bean对象。DispatcherServlet会检查WebApplicationContext中存在的特殊类型bean对象,如果某特殊类型的bean对象在容器中不存在,那么会存在一个回滚机制,使用DispatcherServlet.properties中默认的bean类型来创造bean对象(例如,DispatcherServlet.properties中指定的默认HandlerMapping类型是 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.)。 + +### Servlet Config +在Servlet环境中,可以选择通过java代码的方式或者web.xml的方式来配置servlet容器。 +配置Servlet的详细方式,参照Spring MVC文档。 + +### 请求处理过程 +DispatcherServlet按照如下方式来处理Http请求 +1. 首先,会找到WebApplicationContext并且将其绑定到请求中,此后controller和其他元素在请求处理的过程中可以使用该WebApplicationContext。**默认情况下,WebApplicationContext被绑定到DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE属性中** +2. locale resolver被绑定到请求中,在请求处理过程中可以被其他元素使用 +3. theme resolver被绑定到请求中,在请求处理过程中可以被其他元素使用 +4. 如果指定了multipart file resolver,请求会被检查是否存在multipart。如果multipart被找到,该请求会被包装在一个MultipartHttpServletRequest中并等待对其进行进一步的处理 +5. 一个合适的handler将会被找到,并且和该handler相关联的execution chain(pre/post/Controller)会被执行,返回一个model用于渲染。 +6. 如果model被返回,那么返回的model会被渲染。如果model没有返回,那么没有view会被渲染。 + +在WebApplicationContext中声明的HandlerExceptionResolver会用于解析处理请求中抛出的异常。 +### 路径匹配 +Servlet API将完整的请求路径暴露为requestURI,并且进一步划分requestURI为如下部分:contextPath,servletPath,pathInfo。 +> #### contextPath, servletPath, pathInfo区别 +> - contextPath:contextPath为应用被访问的路径,是整个应用的根路径。默认情况下,SpringBoot的contextPath为"/"。可以通过server.servlet.context-path="/demo"来改变应用的根路径。 +> - servletPath:servletPath代表main DispatcherServlet的路径。默认情况下,servletPath的值仍为"/"。可以通过spring.mvc.servlet.path来自定义该值。 +### Interception +所有HandlerMapping的实现类都支持handler interceptor,当想要为特定请求执行指定逻辑时会相当有用。拦截器必须要实现HandlerInterceptor,该接口提供了三个方法: +- preHandle:在实际handler处理之前 +- postHandle:在 实际handler处理之后 +- afterCompletion:在请求完成之后 +#### preHandle +preHandle方法会返回一个boolean值,可以通过指定该方法的返回值来阻止执行链继续执行。当preHandle的返回值是true时,后续执行链会继续执行,当返回值是false时,DispatcherServlet会假设该拦截器本身已经处理了请求,并不会继续执行execution chain中的其他拦截器和实际handler。 +#### postHandle +对于@ResponseBody或返回值为ResponseEntity的方法,postHandle不起作用,这些方法在HandlerAdapter中已经写入且提交了返回响应,时间位于postHandle之前。到postHandle方法执行时,已经无法再对响应做任何修改,如添加header也不再被允许。对于这些场景,可以**实现ResponseBodyAdvice或者声明一个ControllerAdvice**。 +#### afterCompletion +调用时机位于DispaterServlet渲染view之后。