Spring框架之spring-web web源码完全解析
spring-web是Spring webMVC的基础,由http、remoting、web三部分组成,核心为web模块。http模块封装了http协议中的client/server端的request请求/response响应,编解码,一些格式的转换(如cbor、Rss、json、xml)。remoting模块负责远程调用,包括caucho、httpinvoker、jaxws。
spring-web的web模块封装了快速开发spring-web需要的基础组件。包括:Initializer、accept、bind、client、context、cors、filter、jsf、method、multipart、server、util。
Initializer部分:主要通过web/目录下面的SpringServletContainerInitializer和WebApplicationInitializer做初始化的工作(例如注册servlet或者filtes等)。
accept部分:主要用来负责协商http内容的MIME TYPE是否满足要求的。同一资源可以有多种表现形式,比如xml、json等。具体使用哪种表现形式,是可以协商的。这是RESTfull的一个重要特性,Spring Web MVC也支持这个功能。
bind部分:数据绑定部分,将不同类型的http请求上的数据设置到特定的对象上,如javabean等,支持multipart的绑定。绑定支持两种方式:编程式和注解式。
client部分:客户端部分,核心类RestTemplate,与许多其他Spring 模板类(例如JdbcTemplate、JmsTemplate)设计原则相同,为执行复杂任务提供了一种具有默认行为的简化方法。
context部分:上下文部分,包含了一系列web应用的WebApplicationContext,不同功能的监听器等。
cors部分:对cors跨域资源操作提供了支持。
filter部分:封装了各种不同的过滤器。
jsf部分:增加了对一种以组件为中心的用户界面构建方法的页面表示技术JSF的支持。
method部分:提供给spring mvc使用的方法处理类。
multipart部分:对rfc1867为http协议新增的文件上传功能multipart/form-data提供支持。
server部分:服务器部分。包括ServerWebExchange、WebSession、WebFilter、WebHandler等类。
util部分:提供了公共的工具类。
本文基于version为5.2.4.BUILD-SNAPSHOT的Spring源码版本进行分析,对spring-web web十二个子模块中包含的接口和类进行分析。
一、web/
1.1 SpringServletContainerInitializer
servlet规范规定,在容器启动时,会通过ServletContainerInitializer的实现类来做初始化的工作(例如注册servlet或者filtes等)。
具体使用方法为:
1、实现ServletContainerInitializer接口。(SpringServletContainerInitializer类)
2、在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件。(..\spring-web\src\main\resources\META-INF\services\,tomcat默认就会去读取META-INF)
3、ServletContainerInitializer文件内容为实现类的全类名,即包名+类名。(内容为:org.springframework.web.SpringServletContainerInitializer)
SpringServletContainerInitializer类实现了ServletContainerInitializer接口。这意味着servlet(3.0以上版本)容器启动时,该类被容器自动加载并执行其onStartup(webAppInitializerClasses, servletContext)方法。
SpringServletContainerInitializer 类使用了@HandlesTypes(WebApplicationInitializer.class)注解。表明给onStartup方法传递了类路径下所有实现了WebApplicationInitializer类。spring将初始化所有这些具体实现类,并调用它们的WebApplicationInitializer#onStartup(servletContext)方法。这些类可以在其onStartup方法中,通过可编程方式注册和初始化servlet组件。
简单介绍下Servlet:
Servlet就是一个Java接口,只有5个方法的接口,Servlet接口中的5大方法:
1、void init(ServletConfig):初始化servlet,它是servlet的生命周期方法,由web容器调用一次。
2、void service(ServletRequest, ServletResponse):为传入的请求提供响应,它由容器的每个请求调用。
3、void destroy():仅被调用一次,表明servlet正在被销毁。
4、ServletConfig getServletConfig():返回ServletConfig对象。
5、String getServletInfo():返回有关servlet的信息,如作者、版权、版本等。
Servlet接口定义的是一套处理网络请求的规范,所有实现servlet的类,都要实现它的5个方法。其中最主要的是两个生命周期方法init()和destroy(),还有一个处理请求service()。也就是说所有实现servlet接口的类,或者说,所有想要处理网络请求的类,都要回答三个问题:初始化要做什么,销毁时要做什么,接受到请求时要做什么。
实现了servlet的类能处理请求吗,不能。那请求怎么来到servlet呢,通过servlet容器,比如我们最常用的tomcat。所以需要将servlet部署到一个容器中,否则servlet根本不会起作用。
容器(如tomcat)才是与客户端直接打交道的,它监听了端口,请求过来后,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,tomcat再把这个response返回给客户端。
1.2 WebApplicationInitializer
现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代,它是一个接口。通过实现WebApplicationInitializer,在其中可以添加servlet,listener等,在加载Web项目的时候会加载这个接口实现类,从而起到web.xml相同的作用。
WebApplicationInitializer的调用执行要通过SpringServletContainerInitializer类实现。SpringServletContainerInitializer 类使用了@HandlesTypes(WebApplicationInitializer.class)注解。表明给其onStartup方法传递了类路径下所有实现了WebApplicationInitializer类。spring将初始化所有这些具体实现类,并调用他们的WebApplicationInitializer#onStartup(servletContext)方法。
进入SpringServletContainerInitializer 类的onStartup方法:
1、先判断webAppInitializerClasses这个Set是否为空。
2、如果不为空的话,找到这个Set中不是接口,不是抽象类,并且是WebApplicationInitializer接口实现类的类,将它们保存到List中。
3、判断这个list是否为空,为空则记录日志,返回。
4、不为空的话就按照一定的顺序排序,并将它们按照一定的顺序实例化。调用每一个WebApplicationInitializer的onStartup(servletContext)方法执行。
1.3 HttpRequestHandler
Http请求处理器,一个专门用来处理Http请求,并生成对应的响应的处理器。只有一个handlerRequest方法,其处理逻辑随子类的实现不同而不同。该接口类似于javaEE中的Servlet,目的都是处理请求,产生响应结果。
1.4 HttpMediaTypeException
和媒体类型(Media Types)相关的异常的抽象基类。
1.5 HttpMediaTypeNotAcceptableException
客户端请求期望响应的媒体类型与服务器响应的媒体类型不一致造成的。例如客户端希望返回的媒体类型是json对象(application/json),服务器返回的媒体类型是一个普通的json字符串(text/plain);又或者是客户端希望返回的是html页面,服务器返回的却是json对象。
1.6 HttpMediaTypeNotSupportedException
每条HTTP 请求报文都包含一个方法。这个方法会告诉服务器要执行什么动作,不同于GET、HEAD、DELETE方法,PUT、POST、PATCH方法需要发送客户端数据,HttpRequestHandler处理这三种请求报文时,客户端数据的类型不被支持抛出的异常。
1.7 HttpRequestMethodNotSupportedException
当一个请求报文处理器不支持该请求报文的方法时抛出的异常。一些常见的HTTP方法:
GET:从服务器向客户端发送命名资源;
HEAD:仅发送命名资源响应中的HTTP 首部;
DELETE:从服务器中删除命名资源;
PUT:将来自客户端的数据存储到一个命名的服务器资源中去;
POST:将客户端数据发送到一个服务器网关应用程序;
PATCH:方法是新引入的,是对PUT方法的补充,用来对已知资源进行局部更新。
1.8 HttpSessionRequiredException
一个HttpRequestHandler需要session,但从当前请求获得不到session时抛出的异常。
二、web/accept
accept部分就是负责协商http内容的Mime Type是否满足要求的。几个HTTP请求报文示例:
GET /tools.html HTTP/1.0
User-agent: Mozilla/4.75 [en] (Win98; U)
Host: www.joes-hardware.com
Accept: text/html, image/gif, image/jpeg
Accept-language: en
GET /seasonal/index-fall.html HTTP/1.1
Host: www.joes-hardware.com
Accept: *
HEAD /seasonal/index-fall.html HTTP/1.1
Host: www.joes-hardware.com
Accept: *
rfc-2616中HTTP/1.1中标准头域Accept的语法和语义:
对于实体头域来说,发送者和接收者都既可以指客户端也可以指服务器,取决于谁发送和谁接收此实体。
Accept请求头域被用于指定哪些媒体类型的响应对请求端是可接受的。Accept头域被用于指明请求只对某些期望的媒体类型有效,例如请求一个内嵌的图像。
Accept = "Accept" ":"
#( media-range [ accept-params ] )
media-range = ( "*/*"
| ( type "/" "*" )
| ( type "/" subtype )
) *( ";" parameter )
accept-params = ";" "q" "=" qvalue *( accept-extension )
accept-extension = ";" token [ "=" ( token | quoted-string ) ]
星号”*”字符用于把媒体类型组合成一个范围,“*/*”指明了所有的媒体类型而“type/*”指明type类型的所有子类型。Media-range可能包含一个媒体类型参数。
每一个media-range可能会跟随一个或多个accept-params,以“q”参数指明一个相对的喜爱程度的质量因子。通过,也可以是JSON或XML文档,服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端。
7.10 CorsFilter
跨域请求过滤器。
7.11 FormContentFilter
该过滤器为HTTP的PUT、 PATCH和 DELETE请求解析表单数据,并暴露它为Servlet请求参数。默认情况下,Servlet spec仅要求对HTTP post进行此过滤。
7.12 RelativeRedirectResponseWrapper
Response包装器,主要在RelativeRedirectFilter和 ForwardedHeaderFilter中使用。
7.13 ForwardedHeaderFilter
RFC 7239提出了一个标准化的Forwarded头部,来携带反向代理的基本信息,用于替代X-Forwarded系列及X-Real-IP等非标准化的头部。而ForwardedHeadersFilter提供了Forwarded头部的转发支持。
7.14 RelativeRedirectFilter
Servlet过滤器,将request 请求暴露给当前的线程,主要通过org.springframework.context.i18n.LocaleContextHolder和RequestContextHolder。该过滤器在web.xml中注册。
7.15 AbstractRequestLoggingFilter
上下文信息过滤器 ,定义了两个方法beforeRequest和afterRequest分别用于设定过滤前后执行的操作,它有三个子类,分别是CommonsRequestLoggingFilter、ServletContextRequestLoggingFilter和Log4jNestedDiagnosticContextFilter,这三个子类分别实现了各自的beforeRequest和afterRequest。
7.16 CommonsRequestLoggingFilter
继承自AbstractRequestLoggingFilter,CommonsRequestLoggingFilter在过滤前后分别打印出一段debug的信息。
7.17 ServletContextRequestLoggingFilter
继承自AbstractRequestLoggingFilter,ServletContextRequestLoggingFilter在过滤前后分别向日志文件中写入一段日志信息,日志文件可由log4j.properties等指定。
web/filter/reactive。
7.18 ForwardedHeaderFilter
从"Forwarded"和"X-Forwarded-*"头部提取值,用来重写请求报文的URI。
7.19 HiddenHttpMethodFilter
响应式的webFilter,html中form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求。
7.20 ServerWebExchangeContextFilter
在响应式Context中插入属性(属性名EXCHANGE_CONTEXT_ATTRIBUTE),使得当前的ServerWebExchange可获得。在想访问ServerWebExchange但是又不显示的将其传奇给参与处理请求的组件时有用。
ServerWebExchange 命名为 服务网络交换器 ,存放着重要的请求-响应属性、请求实例和响应实例等等。
八、web/jsf
JavaServer Faces (JSF) 是一种用于构建Java Web 应用程序的标准框架(是Java Community Process 规定的JSR-127标准)。它提供了一种以组件为中心的用户界面(UI)构建方法,从而简化了Java服务器端应用程序的开发。它是一种页面表示技术。
8.1 DecoratingNavigationHandler
JSF NavigationHandler实现类的基类,用来装饰原始的NavigationHandler。
8.2 DelegatingNavigationHandlerProxy
JSF NavigationHandler实现类,代理从Spring root WebApplicationContext容器中获取的NavigationHandler bean。
在faces-config.xml文件中配置该handler proxy。如下:
pre code""
application
...
navigation-handler
org.springframework.web.jsf.DelegatingNavigationHandlerProxy
/navigation-handler
...
/application
/pre
8.3 DelegatingPhaseListenerMulticaster
JSF PhaseListener接口实现类,代理一个或多个从Spring root WebApplicationContext容器中获取的Spring-managed PhaseListener bean。
在faces-config.xml文件中配置该listener multicaster。如下:
pre code""
application
...
phase-listener
org.springframework.web.jsf.DelegatingPhaseListenerMulticaster
/phase-listener
...
/application
/pre
8.4 FacesContextUtils
为一个JSF FacesContext提取Spring的root WebApplication提供功能函数。用于在基于JSF框架的代码中访问Spring的application context情况下。
它类似于Spring中为ServletContext提供功能函数的WebApplicationContextUtils,该类是为FacesContext提供工具包。
web/jsf/el
8.5 SpringBeanFacesELResolver
JSF ELResolver接口的实现类,代理Spring的root WebApplicationContext。将名称引用解析成Spring定义的beans。
在faces-context.xml文件中配置该解析器如下:
pre code""
application
...
el-resolver
org.springframework.web.jsf.el.SpringBeanFacesELResolver
/el-resolver
/application
/pre
8.6 WebApplicationContextFacesELResolver
继承自JSF ELResolver,暴露Spring的WebApplicationContext一个实例,该实例变量的名字为"webApplicationContext"。
九、web/method
9.1 ControllerAdviceBean
该类关于@ControllerAdvice注解的相关信息,spring管理bean,并不要求一定要对其进行实例化。使用函数findAnnotatedBeans(ApplicationContext)可以来查找这种bean。这种bean可以被任何对象创建,包括没有加@ControllerAdvice注解的对象。
对于@ControllerAdvice,我们比较熟知的用法是结合@ExceptionHandler用于全局异常的处理,但其作用不仅限于此。ControllerAdvice拆分开来就是Controller Advice,Advice用于封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ContrllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行“切面”环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。@ControllerAdvice是在类上声明的注解,其用法主要有三点:
结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的;
结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的;
结合方法型注解@ModelAttribute,表示其标注的方法将会在目标Controller方法执行之前执行。
9.2 HandlerMethod
封装了处理函数的信息,包括getMethod()、getBean()。提供了对方法的参数、返回值、注解等等方便的存取方法。
9.3 HandlerTypePredicate
继承自Predicate接口。Predicate接口是JDK8 提供的函数式接口,提供一个抽象方法test, 接受一个参数,根据这个参数进行一些判断,返回判断结果 true/false。
web/method/annotation
9.4 AbstractCookieValueMethodArgumentResolver
抽象基类,用来解析带@CookieValue注解的方法参数。实现的子类会从请求报文中将cookie值提取出来。@CookieValue注解主要是将请求的Cookie数据,映射到功能处理方法的参数上。
9.5 AbstractNamedValueMethodArgumentResolver
该抽象基类用来从命名值(named value)解析方法参数。如请求参数、请求的头部信息、URL路径变量都是命名值。每一个都有一个名字,一个必要的标志、一个默认值。
9.6 AbstractWebArgumentResolverAdapter
使用@WebArgumentResolver的基类,用于向后兼容适配WebArgumentResolver。
9.7 ErrorsMethodArgumentResolver
处理Errors子类参数。
9.8 ExceptionHandlerMethodResolver
在一个给定的类(包括它所有的子类)中找到用@ExceptionHandler注解的方法,然后帮助解析一个给定Exceptin到exception types。
9.9 ExpressionValueMethodArgumentResolver
解析@Value注解的参数。
9.10 RequestHeaderMapMethodArgumentResolver
处理使用@RequestHeader注解的map参数。
9.11 RequestHeaderMethodArgumentResolver
解析使用@RequestHeader注解的参数,不包括map类型。
9.12 RequestParamMapMethodArgumentResolver
处理使用@RequestParam注解的map参数。
9.13 RequestParamMethodArgumentResolver
解析从request流中获取值的参数,如@RequestParam、MultipartFile、Part,默认使用时解析基本参数。
9.14 SessionStatusMethodArgumentResolver
处理SessionStatus类型参数。
9.15 SessionAttributesHandler
SessionAttributesHandler用来处理@SessionAttributes注释的参数,不过它只是做一些宏观的事情,比如,哪个Handler都可以缓存哪些参数、某个参数在当前的SessionAttributes中是否存在、如何同时操作多个参数等,而具体的存储工作是交给SessionAttributeStore去做的,不过SessionAttributeStore并不是保存数据的容器,而是用于保存数据的工具,具体保存数据的容器默认使用的是Session。
9.16 ModelFactory
ModelFactory是用来维护Model的,具体包含两个功能:1、初始化Model。2、处理器执行后将Model中相应的参数更新到SessionAttributes中。
9.17 InitBinderDataBinderFactory
通过@InitBinder注解的方法来初始化WebDataBinder。
9.18 MapMethodProcessor
处理map类型参数。
9.19 ModelMethodProcessor
处理model类型参数。
9.20 ModelAttributeMethodProcessor
解析使用@ModelAttribute注解参数。
9.21 MethodArgumentConversionNotSupportedException
在解析一个方法参数时引发的异常,提供了到目标MethodParameter的访问方法。
9.22 MethodArgumentTypeMismatchException
在解析一个控制器方法参数时引发的异常,提供了到目标MethodParameter的访问方法。
web/method/support
9.23 CompositeUriComponentsContributor
UriComponentsContributor接口的实现类,包含了一列contributors,还封装了一个特定的ConversionService用来将方法参数值转化成字符串格式。
9.24 HandlerMethodArgumentResolver
参数解析器,主要用途:统一封装登录的用户信息;进行数据绑定,参数验证。Spring MVC处理入参靠的是HandlerMethodArgumentResolver这个接口,解析返回值靠的是HandlerMethodReturnValueHandler这个策略接口。
9.25 HandlerMethodArgumentResolverComposite
所有的参数解析器的链表,保存了springMVC提供的所有的参数解析器,采用职责链的模式来完成参数解析器的查找,并完成参数解析生成目标对象。
9.26 HandlerMethodReturnValueHandler
策略接口,用来对调用处理函数之后的返回值进行处理,总共就两个方法;
boolean supportsReturnType();
void handleReturnValue()
9.27 HandlerMethodReturnValueHandlerComposite
springMVC提供的所有的HandlerMethodReturnValueHandler集合,它定义了一个链表用于存储所有实现的HandlerMethodReturnValueHandler。
9.28 AsyncHandlerMethodReturnValueHandler
继承自HandlerMethodReturnValueHandler,支持异步模式。
9.29 InvocableHandlerMethod
InvocableHandlerMethod是对HandlerMethod的扩展,基于一组HandlerMethodArgumentResolver从请求上下文中解析出控制器方法的参数值,然后调用控制器方法。
9.30 ModelAndViewContainer
可以把它定义为ModelAndView上下文的容器,它承担着整个请求过程中的数据传递工作,保存着Model和View。记录HandlerMethodArgumentResolver和 HandlerMethodReturnValueHandler在处理Controller的handler方法时 使用的模型model和视图view相关信息.。
9.31 UriComponentsContributor
帮助构建一个UriComponents,通过查找一个方法参数和参数值,决定目标URL哪一部分需要更新。
十、web/multipart
multipart/form-data请求说明:
先看一个带multipart/form-data的请求报文。假设客户端发送内容构造,接受文件的网页程序位于 http://192.168.29.65/upload_file/UploadFile,我们要发送一个二进制文件、一个文本框表单项、一个密码框表单项。文件名为 E:\s ,其内容如下:(其中的XXX代表二进制数据,如 01 02 03)abbXXXccc 客户端应该向 192.168.29.65 发送如下内容:
POST /upload_file/UploadFile HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.29.65:80
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
Content-Length: 424
Connection: Keep-Alive -----------------------------7d33a816d302b6
Content-Disposition:form-data;
fileContent-Type:
application/octet-stream abbXXXccc
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
foo
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
bar
—-----------------------------7d33a816d302b6—
注意这一行:
Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6
根据 rfc1867,multipart/form-data是必须的。---------------------------7d33a816d302b6 是分隔符,分隔多个文件、表单项。 其中33a816d302b6 是即时生成的一个数字,用以确保整个分隔符不会在文件或表单项的内容中出现。前面的 ---------------------------7d 是 IE 特有的标志。
在最初的http协议中,没有文件上传功能。rfc1867为http协议添加了这个功能:multipart/form-data。客户端浏览器按照此规范将用户指定的文件发送到服务器。服务器端的网页程序(如php、asp、jsp)按照此规范解析出用户发送来的文件。
1、multipart/form-data的基础方式是post,也就是说通过post组合方式来实现的。
2、multipart/form-data于post方法的不同之处在于请求头和请求体。
3、multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,其值也必须为multipart/form-data,同时还需要规定一个内容分割用于分割请求提中多个post的内容,如文件内容和文本内容是需要分隔开来的,不然接收方就无法解析和还原这个文件了,具体的头信息如下:
Content-Type: multipart/form-data; boundary=$${bound}
其中$${bound} 是一个占位符,代表我们规定的分割符,可以自己任意规定,但为了避免和正常文本重复了,尽量要使用复杂一点的内容。如上例中的:--------------------7d33a816d302b6
4、multipart/form-data的请求体也是一个字符串,不过和post的请求提不同的是它的构造方式,post是简单的name=value键值连接,而multipart/form-data是添加了分隔符等内容的构造体。
10.1 MultipartFile
继承自InputStreamSource接口,表示在一个接收到的multipart请求中的上传文件。文件的内容要么存储在内存中,要么暂时存在磁盘中。如果有要求的话,不管采取方式,用户都需要将文件的内容拷贝到会话级别或者永久性的存储中。临时性的存储会在multipart请求处理完毕后进行清空。
10.2 MultipartFileResource
使MultipartFile适配org.springframework.core.io.Resource,以InputStream暴露文件内容,重写方法contentLength()和getFilename()。
10.3 MultipartRequest
这个接口定义了multipart请求的存取操作。该接口被MultipartHttpServletRequest继承。
10.4 MultipartHttpServletRequest
继承自HttpServletRequest、MultipartRequest。在servlet request中提供了额外的方法,专门用来处理multipart内容,允许存取上传的文件。
10.5 MultipartResolver
MultipartResolver 用于处理文件上传,当收到请求时 DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart() 方法判断请求中是否包含文件。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest)对象中,最后传递给 Controller,在 MultipartResolver 接口中有如下方法:
boolean isMultipart(HttpServletRequest request); // 是否是 multipart
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request); // 解析请求
void cleanupMultipart(MultipartHttpServletRequest request);
10.6 MultipartException
multipart解析失败时抛出的异常。
10.7 MaxUploadSizeExceededException
继承自MultipartException,当上传的文件大小超过了最大限制时抛出的异常。
web/multipart/commons
10.8 CommonsFileUploadSupport
使用Apache的Commons FileUpload组件(1.2或者更高的版本)的multipart解析器的基类。
10.9 CommonsMultipartFile
MultipartFile接口的实现类,专为Apache Commons FileUpload。
10.10 CommonsMultipartResolver
使用 commons Fileupload 来处理 multipart 请求。在使用时要引入相应的 jar 包。
web/multipart/support
10.11 MultipartFilter
Servlet过滤器,在root WebApplicationContext容器中通过一个MultipartResolver来解析multipart请求。
10.12 MultipartResolutionDelegate
HandlerMethodArgumentResolver接口实现类的一个通用代理,用来解析MultipartFile和Part参数。
10.13 AbstractMultipartHttpServletRequest
MultipartHttpServletRequest接口实现类的抽象基类。提供了对预生成的MultipartFile实例的管理。
10.14 DefaultMultipartHttpServletRequest
MultipartHttpServletRequest接口的默认实现,提供了对预生成的参数值的管理。该类在CommonsMultipartResolver中使用。
10.15 RequestPartServletServerHttpRequest
ServerHttpRequest接口的实现类,用来存取multipart请求的一部分。如果使用MultipartResolver配置,该部分就通过MultipartFile进行存取。如果使用Servlet 3.0进行multipart处理,该部分就通过ServletRequest.getPart进行存取。
10.16 StandardMultipartHttpServletRequest
Spring MultipartHttpServletRequest的适配器,包装了一个ervlet 3.0 HttpServletRequest和它的Parts对象。
10.17 StandardServletMultipartResolver
基于 Servlet 3.0来处理 multipart 请求的,所以不需要引用其他 jar 包,但是必须使用支持 Servlet 3.0的容器才可以,以tomcat为例,从 Tomcat 7.0.x的版本开始就支持 Servlet 3.0了。
10.18 ByteArrayMultipartFileEditor
个性化的java.beans.PropertyEditor,用来将MultipartFiles转换成字节数组。
10.19 StringMultipartFileEditor
个性化的java.beans.PropertyEditor,用来将MultipartFiles转换成字符串。允许指定使用的字符集。
10.20 MissingServletRequestPartException
当通过名字进行寻找一个"multipart/form-data" 请求的一部分,但是查找不到时抛出异常。
十一、web/server
11.1 ServerWebExchange
ServerWebExchange名为服务网络交换器,是一个HTTP请求-响应交互的契约。提供对HTTP请求和响应的访问,并公开额外的服务器端处理相关属性和特性,如请求属性。存放着重要的请求-响应属性、请求实例和响应实例等等,有点像Context的角色。
11.2 ServerWebExchangeDecorator
ServerWebExchange装饰类,用于需要封装一个ServerWebExchange的类的基类,通过委托给包装实例预实现所有方法。
11.3 DefaultServerWebExchangeBuilder
ServerWebExchange的内部接口ServerWebExchange.Builder的实现类。
11.4 WebSession
使用服务器端会话的主要约定,提供了同HTTP请求间会话属性的访问。创建WebSession实例并不会自动开启一个会话。会话属性添加完毕后,调用WebSession.start()函数才开启一个会话,继而将会话id发送到客户端(比如通过cookie)。
Cookie机制和Session机制用来唯一标识一个用户,同时记录该用户的状态。cookie是存储子在客户端,而Session是存储在服务器端。
Session机制:采用的是在服务器端保持Http状态信息的方案。服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即sessionId),如果已经包含一个sessionId则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用。如果客户请求不包含sessionId,则为此客户创建一个session并且生成一个与此session相关联的sessionId,这个sessionId将在本次响应中返回给客户端保存。
11.5 WebFilter
使用拦截器链的方式来处理web请求的约定,主要被用来实现横切请求,比如安全。
11.6 WebFilterChain
过滤器链,使得链中的web过滤器转到下一个。
11.7 WebHandler
处理一个web请求。该接口定义了一个函数handle(ServerWebExchange exchange)。
11.8 WebExceptionHandler
对在执行处理ServerWebExchange时发生的异常进行处理。
11.9 ResponseStatusException
和指定的HTTP响应状态码相关的异常的基类。
11.10 ServerWebInputException
Spring web应用中遇到了响应状态码400(400 bad request,请求报文存在语法错误)抛出的异常。
11.11 MethodNotAllowedException
接收到响应状态码405(Method Not Allowed,请求行中指定的请求方法不能被用于请求相应的资源。)时抛出的异常。
11.12 ServerErrorException
HttpStatus为INTERNAL_SERVER_ERROR(服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。)时抛出的异常。
11.13 NotAcceptableStatusException
发生response status 406(Not Acceptable请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。)抛出的异常。
11.14 MediaTypeNotSupportedStatusException
发生response status 415(Unsupported Media Type,对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。)抛出的异常。
11.15 UnsupportedMediaTypeStatusException
发生response status 415(Unsupported Media Type,对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。)抛出的异常。
web/server/adapter
11.16 AbstractReactiveWebInitializer
继承自AbstractReactiveWebInitializer的类,可以在servlet容器中安装一个Spring Reactive Web Application。它通过将ServletHttpHandlerAdapter实例作为一个servlet安装到servler容器中。
11.17 DefaultServerWebExchange
ServerWebExchange接口的默认实现类。
11.18 ForwardedHeaderTransformer
处理HTTP头部,包括提取和移除某些头部键值对,或者只移除。
11.19 HttpWebHandlerAdapter
WebHandler的适配器。默认情况下创建和配置一个DefaultServerWebExchange,然后调用目标WebHandler。
11.20 WebHttpHandlerBuilder
此构建器有两个用途:
一是用来组装由目标WebHandler组成的处理链,使用一系列的WebFilters来装饰,更进一步的装饰使用一系列的WebExceptionHandlers。
二是借助HttpWebHandlerAdapter适配器使生成的处理器链适配一个HTTPHandler。
web/server/handler
11.21 DefaultWebFilterChain
WebFilterChain接口的默认实现,该类的每一个实例都表示链中的一个对象,构造器DefaultWebFilterChain(WebHandler, List)初始化了整个链,并执行链中面,一般我们称之为多语言。springMVC国际化机制就是可以设置整个系统的运行语言。
LocaleContext该接口决定当前真正的Locale。
LocaleContextResolver:该接口用于解析基于web的local contex,允许通过request决定这个local context或者通过HTTP exchange来修改这个local contex。
11.27 AcceptHeaderLocaleContextResolver
LocaleContextResolver接口的实现类,解析器检查HTTP request中携带的"Accept-Language" 请求头,通常该请求头字段中包含了客户端地区信息。(这个地区信息由客户端浏览器发送,在客户端的操作系统中体系)。该解析器不支持设置LocalContext,
11.28 FixedLocaleContextResolver
LocaleContextResolver接口的实现类,一直使用固定的Local,不支持改变Local。默认的为JVM的默认local。
web/server/session
11.29 WebSessionIdResolver
WebSessionIdResolver定义了session id解析策略的契约。允许通过请求解析session id,并通过响应来发送session id或者终止会话。包含三个方法:
resolveSessionIds(ServerWebExchange exchange):解析与当前请求相关联的sessionId。sessionId可能来自Cookie或请求头。
setSessionId(ServerWebExchange exchange, String sessionId):将给定的sessionId发送给客户端。这个方法是在创建一个新session时被调用,并告知客户端新sessionId是什么。
expireSession(ServerWebExchange exchange):指示客户端结束当前session。当session无效时调用此方法,并应通知客户端sessionId不再有效。比如,它可能删除一个包含sessionId的Cookie,或者设置一个HTTP响应头,其值为空就表示客户端不再提交sessionId。
11.30 CookieWebSessionIdResolver
基于Cookie的WebSessionIdResolver。
11.31 HeaderWebSessionIdResolver
WebSessionIdResolver接口的实现类,通过从请求头header中解析出sessionId。
11.32 WebSessionManager
WebSession管理器,为HTTP request提供了访问WebSession的方法。该接口定义了一个方法getSession(),为一个给定的ServerWebExchange返回WebSession。
11.33 DefaultWebSessionManager
实现了WebSessionManager接口,主要定义了session的创建,启动,暂停与cookie的关联的定义。
11.34 WebSessionStore
会话存储接口,为WebSession持久化保存的策略接口。包含4个函数:
1、createWebSession()创建一个新的WebSession,该函数仅是创建一个会话实例,会话的启动通过WebSession#start()函数,持久化通过WebSession#save()函数。
2、retrieveSession(String sessionId);根据给定的sessionId返回相应的WebSession。
3、removeSession(String sessionId);删除指定sessionId的WebSession。
4、updateLastAccessTime(WebSession webSession):更新webSession的时间戳为当前时间。
11.35 InMemoryWebSessionStore
WebSessionStore接口的默认实现,采用map集合的方式来存储WebSession实例。
十二、web/util
12.1 ContentCachingRequestWrapper
把请求内容缓存起来的代理类。servlet的request body一旦流被读取了,就无法再次消费了,通过这个类能够解决HttpServletRequest inputStream只能读取一次的问题(request.getInputStream())。它使用一个字段:cachedContent来缓存body体里面的内容。
12.2 ContentCachingResponseWrapper
把响应内容缓存起来的代理类。缓存所有要写入getOutputStream()和getWriter()中的内容,允许该内容通过函数getContentAsByteArray()获得。
12.3 HtmlCharacterEntityDecoder
帮助类,通过使用实体字符(the referred character)来替换字符实体编码(character entity references)进行HTML字符串的解码操作。
12.4 HtmlCharacterEntityReferences
表示在HTML4.0标准中定义的一系列字符实体编码。完整的描述在https://www.w3.org/TR/html4/charset.html中。
12.5 HtmlUtils
很多时候,由于特殊字符的原因,会造成用户输入的信息反馈到页面上时会显示成乱码,造成页面排版混乱;另外,黑客经常利用特殊字符对网站进行xss跨站攻击,所以我们需要对页面上提交的特殊字符进行html转码。
转换为HTML转义字符表示、转换为数据转义表示、转换为十六进制数据转义表示。
12.6 JavaScriptUtils
基于JavaScript 1.5 recommendation对JavaScript进行转义。
12.7 WebUtils
WebUtils:该工具类主要用于Web应用程序,供各种框架使用。主要方法如下:
1、setWebAppRootSystemProperty:表示保存系统根路径的key-value
2、removeWebAppRootSystemProperty:表示移除系统根路径的key-value。
3、getDefaultHtmlEscape:看web.xml中的defaultHtmlEscape的值是否设置为true。
4、getTempDir:返回由当前servlet容器提供的 当前Web应用程序的临时目录。
5、getRealPath:返回由servlet容器提供的,Web应用程序中给定路径的实际路径。
6、getSessionId:返回指定的request的session id。
7、get/setSessionAttribute:根据当前的request和session attributes的name得到/设置session attributes的值。
8、getNativeRequest:返回指定类型的合适的请求对象,如果可用,会unwrapping给定的request请求。
9、getNativeResponse:返回指定类型的response对象。
10、isIncludeRequest:判断请求是否是一个包含(Include)请求,即不是从外部进入的顶级Http请求。
11、getCookie:获取制定名字的cookie。
12、getParametersStartingWith:返回包含具有给定前缀的所有参数的map。将单个值映射为String,多个值映射到String数组。
12.8 ServletContextPropertyUtils
用来解析文本中的占位符,常在文件路径中使用。
12.9 TagUtils
jsp标签的工具支持类。
12.10 UriUtils
处理uri里特殊字符的编码。
12.11 HttpSessionMutexListener
HttpSessionListener接口实现类,该Servlet HTTP 会话监听器会在一个Http会话创建的时候暴露会话的互斥锁。该监听器在web.xml中注册。
12.12 IntrospectorCleanupListener
1、此监听器主要用于解决java.beans.Introspector导致的内存泄漏的问题。
2、此监听器应该配置在web.xml中与Spring相关监听器中的第一个位置(也要在ContextLoaderListener的前面)。
3、JDK中的java.beans.Introspector类的用途是发现Java类是否符合JavaBean规范,如果有的框架或程序用到了Introspector类,那么就会启用一个系统级别的缓存,此缓存会存放一些曾加载并分析过的JavaBean的引用。当Web服务器关闭时,由于此缓存中存放着这些JavaBean的引用,所以垃圾回收器无法回收Web容器中的JavaBean对象,最后导致 内存变大。
而org.springframework.web.util.IntrospectorCleanupListener就是专门用来处理Introspector内存泄漏问题的辅助类。IntrospectorCleanupListener会在Web服务器停止时清理Introspector缓存,使那些Javabean能被垃圾回收器正确回收。Spring自身不会出现这种问题,因为Spring在加载并分析完一个类之后会马上刷新JavaBeans Introspector缓存,这就保证Spring中不会出现这种内存泄漏的问题。但有些程序和框架在使用了JavaBeans Introspector之后,没有进行清理工作(如 Quartz,Struts),最后导致内存泄漏。
12.13 WebAppRootListener
这个listener的作用就是监听web.xml中的配置param-name为webAppRootKey的值:
context-param
param-name webAppRootKey /param-name
param-value myroot /param-value
/context-param
然后配置这个监听器:
listener
listener-class org.springframework.web.util.WebAppRootListener /listener-class
/listener
作用:它会在ServletContext上下文初始化的时候,首先获取根传递进来的servletContext得到物理路径,String path=servletContext.getRealPath(""/"");然后找到context-param的webAooRootKey对应的param-value,把param-value的值作为key,上面配置的是""myroot""。
接着执行System.setProperty(""myroot"",path)。这样在web中任意地方就可以使用System.getProperty(""myroot"")来获取系统的绝对路径。
12.14 UriBuilder
URIBuilder主要用于构造URI,URI(Uniform Resource Identifier)即通一资源标志符,表示的是web上每一种可用的资源,如 HTML文档、图像、视频片段、程序等都由一个URI进行定位的。URL是URI的一个子集,它是Uniform Resource Locator的缩写,译为"统一资源定位符"。
12.15 UriBuilderFactory
用来创建UriBuilder实例。
12.16 DefaultUriBuilderFactory
UriBuilderFactory接口的实现类。依靠UriComponentsBuilder来实际创建一个URI。
12.17 UriComponents
表示一系列的不可改变的URI组件,将组件类型映射到字符串值。包含了所有组件的getters方法。实际上,同java.net.URI类似,不过拥有更强的编码选择,支持URI template变量。
12.18 OpaqueUriComponents
拓展自UriComponents,支持opaque URIs。
12.19 HierarchicalUriComponents
拓展自UriComponents,支持hierarchical URIs。
12.20 UriComponentsBuilder
Spring MVC 提供了一种机制,可以构造和编码URI – 使用UriComponentsBuilder和UriComponents。这样我们不再自己去拼接了,提高了正确性。它可以细粒度的控制URI的各个要素,如构建、扩展模板变量以及编码。
12.21 UriTemplate
用于处理格式化Uri模板。
12.22 UriTemplateHandler
定义了用来拓展URI模板类的方法。
12.23 AbstractUriTemplateHandler
UriTemplateHandler接口实现类的抽象基类。提供了setBaseUrl和setDefaultUriVariables方法,在子类中不管是URI模板的拓展还是编码机制都是密切相关的。
12.24 DefaultUriTemplateHandler
UriTemplateHandler接口的默认实现,使用UriComponentsBuilder来扩展和编码uri的。
12.25 UrlPathHelper
Spring用来处理URL的工具类,位于包org.springframework.web.util内。它帮助Spring MVC处理URL相关的各种难题。
12.26 CookieGenerator
生成Cookie。一般在CAS单点登录里用得较多。现在都用JWT了,就用得较少了。CAS (Central Authentication Server) 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法。
Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。
12.27 NestedServletException
继承自ServletException,从message和stacktrace角度来说,是在root处引发的异常,就像NestedChecked/RuntimeException。
web/util/pattern
12.28 SubSequence
用来返回一个数组的一个部分,当要把一个数据的子集传给另外一个函数但是不希望创建一个新的字符串对象时有用。
12.29 PathPattern
表示一个解析过的路径模式。包含一系列的路径元素用来快速匹配。
12.30 PathPatternRouteMatcher
RouteMatcher接口实现类,属性中包含了一个PathPatternParser对象,该类使用PathContainer和PathContainer表示route和patterns。
12.31 PathPatternParser
解析URI path patterns产生PathPattern实例对象,从而匹配request请求。
12.32 InternalPathPatternParser
解析URI template patterns。它把path pattern分解成许多PathElements,这些PathElements以链表形式组织。这些实例可重复使用,但是是非线程安全的。
12.33 PatternParseException
解析pattern时发生问题时抛出的异常。
12.34 PathElement
由抽象语法树节点创建,用来表示一个路径模式的通用超类。
12.35 LiteralPathElement
一个文字的路径元素。在'/foo/bar/goo'模式中,有三个文件的路径元素:'foo', 'bar'和 'goo'。
12.36 RegexPathElement
正则表达式的路径元素。用来表示复杂的路径元素。比如在'/foo/*_*/*_{foobar}' 中, *_* 和*_{foobar}都是正则表达式的路径元素。
12.37 SeparatorPathElement
路径分隔符元素,在模式'/foo/bar'总,两次出现的'/'可以使用SeparatorPathElement类进行表示(如果默认的分隔符是'/')。
12.38 CaptureVariablePathElement
路径中某一块是个变量,那么这个变量元素可以使用CaptureVariablePathElement表示。比如在'/foo/{bar}/goo' 中,{bar}就可以用该类表示。
12.39 WildcardPathElement
通配符路径元素。在'/foo/*/goo'中,这个*就可以用WildcardPathElement来表示。在整个路径上(如上例),至少要匹配一个字符,但是在一个路径的的末尾(如linux*),可以匹配0个字符。
12.40 SingleCharWildcardedPathElement
一个文字路径元素,该元素包括一个或多个通配符'?'(一个?通配符代替一个字符)。
12.41 CaptureTheRestPathElement
一个路径元素,表示捕获路径的其余部分,在'/foo/{*foobar}' 中/{*foobar}就可以用CaptureTheRestPathElement表示。
12.42 WildcardTheRestPathElement
一个路径元素,表示通配路径的其余部分。在'/foo/**'中/**就可以用WildcardTheRestPathElement来表示。
本文参考了博客园、CSDN部分文献。
拓展阅读:
Spring框架之beans源码完全解析
Spring框架之AOP源码完全解析
Spring框架之jdbc源码完全解析
Spring源码深度解析之数据库连接JDBC
Spring框架之jms源码完全解析
Spring框架之事务源码完全解析
Spring源码深度解析之事务
Spring源码深度解析之Spring MVC
Spring框架之websocket源码完全解析
WebSocket协议中文版
Spring框架之spring-web web源码完全解析
Spring框架之spring-web http源码完全解析
Spring框架之spring-webmvc源码完全解析