Spring-webmvc模块主要用于在遵守servlet规范的前提下将Spring框架集成到java web 应用
springmvc启动过程:容器加载ContextLoaderListenr,调用contextInitialized()(内部调用initWebApplicationContext方法)
ContextLoaderListener:Spring的ApplicationContext加载类,继承ContextLoader类,实现ServletContextListener接口
核心方法:
1.initApplicationContext
2.createWebApplicationContext
备注:默认使用的是XmlWebApplicationContext
3.configureAndRefreshWebApplicationContext
DispatcherServlet:http请求应答核心处理器,集成了springmvc框架的各个组件
请求应答流程如下:
核心方法:
1.doService
2.doDispatch
UML类图结构如下:
HttpServletBean: 负责将init-param参数值保存到当前类型的同名属性
FrameworkServlet:Spring Web框架的基本servlet,根据web.xml或者注解的context配置参数集成Spring应用程序上下文
核心方法:
1.initServletBean()
2.initWebApplicationContext()
WebApplicationContext查找顺序:
1.配置已设置的webapplicationContext:主要配置ServletContext和ServletConfig,添加ContextRefreshListener等
2.查找webapplicationContext:根据ContextAttribute属性查找对应的webapplicationContext
3.创建webapplicationContext: 根据ContextClass和ContextConfigLocation属性创建webapplicationContext
HandlerMapping:负责定义HttpServletRequest与handler之间映射的接口
UML类图结构如下:
AbstractHandlerMapping:HandlerMapping接口的抽象实现,包含默认handler和handler interceptors
初始化过程:
核心方法:
1.getHandler
备注:用于根据HttpSerlvetRequest获取对应的HandlerExecutionChain。在涉及IO的编程模型中,大量使用装饰器模式
AbstractHandlerMethodMapping:定义了HttpServletRequest与HandlerMethod之间的映射,每个HandlerMethod只对应唯一一个HandlerMapping
初始化过程:
1.initHandlerMethods
2.registerHandlerMethod
运行过程:
1.getHandlerInternal
2.lookupHandlerMethod
RequestMappingInfoHandlerMapping:使用RequestMappingInfo类型定义HttpServletRequest与handlerMethod之间的映射
核心方法:
1.handleMatch
RequestMappingInfo:RequestCondition类型的聚合类,主要功能是合并其他的RequestMappingInfo对象的各个RequestCondition,根据HttpServletRequest获取满足条件的RequestMappingInfo,在同一个HttpServletRequest的基础上与其他的requestInfo对象进行比较
核心方法:
1.combine
2.getMatchingCondition
3.compareTo
类型 | 描述 | 核心逻辑 |
---|---|---|
PatternsRequestCondition | 判断HttpServletRequest的url是否满足特定的格式 | getMatchingCondition |
RequestMethodsRequestCondition | 根据HttpServletRequest的Http请求方法(GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE)筛选出对应的RequestMethodsRequestCondition | getMatchingCondition |
ParamsRequestCondition | 根据HttpServletRequest的Parameter或ParameterMap的内容进行过滤 | 内部类:ParamExpression getMatchingCondition
|
RequestMappingHandlerMapping:在Controller注解应用的类上使用RequestMapping注解(应用于类型和方法)创建RequestMappingInfo实例
1.getMappingForMethod
备注:根据RequestMapping注解的内容生成RequestMappingInfo对象,并根据HttpServletRequest和pattern进行匹配
HandlerExceptionResolver:处理handler映射和运行时抛出异常的接口。具体实现可以登记到ApplicationContext对象中
UML类结构图如下:
AbstractHandlerExceptionResolver:HandlerExceptionResolver接口的抽象实现
核心方法
1.resolveException
AbstractHandlerMethodExceptionResolver:支持处理HandlerMethod类型抛出异常的抽象类型
核心方法:
1.doResolveException
ExceptionHandlerExceptionResolver:待分析
HandlerAdapter:处理HttpServletRequest请求的handler基本接口,DispatcherServlet直接使用HandlerAdapter接口类型处理请求
UML结构图如下:
具体实现如下:
AbstractHandlerMethodAdapter:支持HandleMethod类型handler的基类
RequestMappingHandlerAdapter:读取RequestMapping定义来帮助HandlerMethod方法实现和处理其方法参数和返回类型
可以通过setCustomArgumentResolvers和setCustomReturnValueHandlers添加对自定义参数和返回值类型的支持
初始化过程如下:
1.initControllerAdviceCache:查找applicationContext中注解为ControllerAdvice的bean,并把bean和包含注解为RequestMapping或者ModelAttribute的方法,包含注解为InitBinder的方法添加到局部列表
2.初始化argumentResolvers
3.初始化initBinderArgumentResolvers
初始化内容同上
4.初始化returnValueHandlers
请求处理过程如下:
invokeHandlerMethod处理过程:
总体分为3个阶段:
1.设置ServletInvocableHandlerMethod对象
2.ServletInvocableHandlerMethod对象invocableMethod调用invokeAndHandle方法
3.返回ModelAndView对象
InvokeForRequest具体实现:
1.获取方法参数值:遍历方法参数列表的过程中,argumentResolvers将HttpServletRequest内容转化为方法参数值
(argumentResolvers.supportsParameter()=>argumentResolvers.resolveArgument())
2.调用bridgeMethod: getBridgedMethod().invoke(getBean(), args)
returnValueHandlers.handleReturnValue具体实现:
1.选择处理器:遍历returnValueHandlers,查找到对应handler(handler.supportsReturnType())
2.处理器实际处理返回值
HandlerExecutionChain:处理程序执行链,由Handler对象和HandlerInteceptor列表组成
核心方法 | 描述 | 代码片段 |
---|---|---|
applyPreHandle | 调用拦截器链的preHandle方法:如果preHandle方法返回false, 调用triggerAfterCompletion方法并且请求不再进行处理 |
|
applyPostHandle | 调用拦截器链的postHandle方法 | |
triggerAfterCompletion | 调用拦截器链的afterCompletion方法 |
HandlerMethodArgumentResolver:将HttpServletRequest请求的内容绑定对应方法参数值
UML类图如下:
接口方法:
1.boolean supportsParameter(MethodParameter parameter): 是否该parameter参数由当前解析类支持。
2.Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception: 从MethodParameter对象解析出参数值
AbstractMessageConverterMethodArgumentResolver:通过HttpMessageConverter读取HttpServetRequest body 来绑定HandlerMapping 方法请求参数
属性:
protected final List<HttpMessageConverter<?>> messageConverters; //核心对象
protected final List<MediaType> allSupportedMediaTypes;
private final RequestResponseBodyAdviceChain advice; //责任链模式
构造函数:
/**
* Constructor with converters and {@code Request~} and {@code ResponseBodyAdvice}.
* @since 4.2
*/
public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
@Nullable List<Object> requestResponseBodyAdvice) {
Assert.notEmpty(converters, "'messageConverters' must not be empty");
this.messageConverters = converters;
this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice);
}
备注:allSupportedMediaTypes从messageConverter.getAllSupportedMediaTypes聚合得来
核心方法:
1.readWithMessageConverters
/**
* Create the method argument value of the expected parameter type by reading
* from the given HttpInputMessage.
* @param <T> the expected type of the argument value to be created
* @param inputMessage the HTTP input message representing the current request
* @param parameter the method parameter descriptor
* @param targetType the target type, not necessarily the same as the method
* parameter type, e.g. for {@code HttpEntity<String>}.
* @return the created method argument value
* @throws IOException if the reading from the request fails
* @throws HttpMediaTypeNotSupportedException if no suitable message converter is found
*/
@SuppressWarnings("unchecked")
@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class<?> contextClass = parameter.getContainingClass();
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class<T>) resolvableType.resolve();
}
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (logger.isDebugEnabled()) {
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
}
if (message.hasBody()) {
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
}
else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
}
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
return body;
}
流程如下:
AbstractNamedValueMethodArgumentResolver:用于从命名值解析方法参数的抽象基类。请求参数,请求标头和路径变量是已命名的示例值。 每个可以有一个名称,一个必需的标志和一个默认值
核心方法:
1.resolveArgument
执行过程:
Annotation-based Resolver:继承自AbstractNamedValueMethodArgumentResolver,通过注解的方式将HttpServletRequest里面的内容转化为对应对象
UML结构图如下:
ModelAttributeMethodProcessor:解析注解为ModelAttribute的方法参数和方法返回值
Type-based Resolver:将HttpServletRequest请求内容绑定到HandleMethod方法的请求参数类型
ViewResolver:Web应用程序的所有MVC框架都提供了一种展示视图的途径。Spring提供了视图解析器(ViewResolver):使您能够在浏览器中灵活地渲染模型,而不用考虑一个特定的视图技术。Spring的视图解析器能够方便,灵活地使用JSP页面,Velocity模板和XSLT技术输出返回结果
View类UML结构图:
View类列表:
AbstractView:提供对静态属性的支持,以供视图使用:可以通过各种方法来指定静态属性。静态属性可以合并到具体的model对象中,在视图中展示出来
核心方法:
1.render
2.createMergedOutputModel
备注:创建一个包含静态属性,路径变量,model和RequestContext的组合model(动态值优先于静态属性)
renderMergedOutputModel: 实际展示抽象方法:所有的具体视图必须重写这个方法
第一步准备请求:在JSP视图中,意味着将模型对象保存为请求属性。
第二步负责视图的实际呈现,例如包括通过RequestDispatcher的include或者forward方法访问JSP页面
FreeMarkerView:使用FreeMarker模板引擎的视图
核心方法:
1.initServletContext
2.doRender
InternalResourceView:用于访问Web应用程序的JSP或其他资源的包装器视图。url属性指定了Web的资源,能够传递到RequestDispatcher的forward或者include方法中
核心方法:
1.renderMergeOutputModel
ViewResolver类UML结构图如下:
ContentNegotiatingViewResolver:优先级最高,根据文件名或者HTTP头部信息的Accept字段委托给具体的视图解析类进行视图解析(contentNegotiationManager负责具体的映射工作)
核心方法:
1.Bean初始化
2.resolveViewName
UrlBasedViewResolver: ViewResolver接口的简单实现.允许直接通过请求URL映射到View名称
核心方法:
1.initApplicationContext
检验viewClass属性是否为空
2.createView
备注:添加redirect和forward特殊处理逻辑
3.loadView