一、HandlerMapping
- 继承体系
- AbstractHandlerMapping
- AbstractUrlHandlerMapping系列
- AbstractHandlerMethodMapping系列
二、HandlerAdapter
- RequestMappingHandlerAdapter概述
- RequestMappingHandlerAdapter自身结构
- 总结
三、ViewResolver
四、RequestToViewTranslator
五、HandlerExceptionResolver
六、MultipartResolver
- StandardServletMultipartResolver
七、SpringMVC原理总结
- 原理总结
- 跟踪一个请求处理流程详细过程
一、HandlerMapping 1、继承体系
可以看到HandlerMapping家族的成员可以分为两支,其下第一个抽象类为AbstractHandlerMapping
- 一支继承AbstractUrlHandlerMapping
- 一支继承AbstractHandlerMethodMapping
概述
- 是HandlerMapping的抽象实现,下面所有的XxxHandlerMapping都继承他
- 采用模板模式设计了HandlerMapiing实现的整体结构,子类只需要通过模板方法提供一些初始值或者具体的算法即可,首先使用一个抽象类实现采用模板模式进行整体设计,然后子类通过实现模板方法具体完成业务。
- HandlerMapping的作用是根据request查找Handler和Interceptors,获取Handler的过程通过模板方法getHandlerInternal交给了子类。
- AbstractHandlerMapping保存了所有配置的Interceptor,在获取到Handler之后会自己根据从request提取的lookupPath将相应的Interceptors装配上去
- 子类可以通过getHandlerinternal方法设置自己的Interceptor,返回值类型为Object
概述
- 先看类继承实现public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered, BeanNameAware {}
- 父类WebApplicationObjectSupport ,初始化会自动调用模板方法initApplicationContext,,也就是子类AbstractHandlerMapping的入口方法
- AbstractHandlerMapping的创建就是在initApplicationContext方法里面实现的
// WebApplicationObjectSupport 模板方法,调用子类的
protected void initApplicationContext(ApplicationContext context) {
super.initApplicationContext(context);
if (this.servletContext == null && context instanceof WebApplicationContext) {
this.servletContext = ((WebApplicationContext)context).getServletContext();
if (this.servletContext != null) {
this.initServletContext(this.servletContext);
}
}
}
// AbstractHandlerMapping 的 入口方法
protected void initApplicationContext() throws BeansException {
// 1. 模板方法,用于给子类提供添加、修改Interceptors的入口,不过现有的SpringMVC没有使用
this.extendInterceptors(this.interceptors);
// 2. 将SpringMVC容器及父容器中 所有的 MappedInterceptor类型的Bean添加到adaptedInterceptors成员属性
this.detectMappedInterceptors(this.adaptedInterceptors);
// 3. 初始化Interceptor,具体的内容是将 全部interceptors所包含的对象按照类型添加到装配好的adaptedInterceptors成员属性
this.initInterceptors();
}
// 成员属性
// 全部的Interceptors,作为汇总列表使用
private final List
成员属性概述
-
List
-
List
adaptedInterceptors:这种类型的Interceptor不需要在进行匹配,在getHandler中会全部添加到返回值HnadlerExecutionChain里面,或者是使用时与请求的url进行匹配,从detectMappedInterceptors()方法获取添加到HnadlerExecutionChain里面
HandlerMapping是通过getHandler方法处理处理器Handler和Interceptor的,实现分为两部分
- 第一部分:找Handler
- 第二部分:添加Interceptors
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 第一部分,找Handler
// 1. 模板方法,子类需要做的事情
Object handler = this.getHandlerInternal(request);
if (handler == null) {
// 2. 没有找到,使用默认的,保存早该类的成员属性defaultHandler,可以在配置HandlerMapping的时候配置,也可以在子类配置
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
// 3. 找到是String类型,则根据名字去SpringMVC的容器查找响应的Bean
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
// 第二部分
// 1. 根据Handler创建 executionChain 执行链对象
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
// 1. getHandlerExecutionChain()方法
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 根据handler创建chain对象
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
// 之前装配好的拦截器
Iterator var5 = this.adaptedInterceptors.iterator();
while(var5.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
3、AbstractUrlHandlerMapping系列
概述
- 该系列的类都继承AbstractUrlHandlerMapping,它是根据url匹配的。
- 此系列的大致原理是将url和对应的handler保存在一个Map中,在getHandlerInternal方法使用url从Map中获Handler
- AbstractUrlHandlerMapping完成了url查找handler的过程,对于map的初始化工作交给子类完成,这里的map就是定义在AbstractUrlHandlerMapping的成员变量handlerMap
- 另外还定义了处理/请求的rootHandler,定义在成员变量private Object rootHandler
主要问题就是
- 怎么获取handler的?
- 这个Map是由子类怎么创建的?
获取handler的入口是在子类 实现AbstractHandlerMapping模板方法getHandlerInternal()里面,也就是AbstractUrlHandlerMapping的getHandlerInternal()
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
// 一、用于使用lookupPath从Map找Handler,不过很多时候不能直接从Map中get到,
// 1. 因为很多的Handler都是使用Pattern的匹配模式,如/xiaosi
// 不设置的的话,默认从AbstractHandlerMethodAdapter中直接传入false,不对请求方式限制
@Nullable
private Set supportedMethods;
protected final void checkRequest(HttpServletRequest request) throws ServletException {
// Check whether we should support the request method.
String method = request.getMethod();
// 默认不检查,请求的类型是否支持
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
}
// Check whether a session is required.
// 默认也是不检查,如果session是必须存在的,判断session是否真实存在
if (this.requireSession && request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
执行请求处理
-
首先创建ServletWebRequest对象
// 在ArgumentResolver解析参数时候的request就是这个对象,处理器需要HttpServletRequest,这是ArgumentResolver就会转换设置 -
初始化3个变量
// 2.1用于参数跟String之间的类型转换,ModelFactory 刷新也会用到它:// 将符合条件注释了@InitBinder的方法找出来,这些方法主要用于处理参数
// 2.2主要是处理Model的,主要包含两个功能,1. 在处理器具体处理之前对Model初始化, 2. 再处理完成请求后对Model参数更新
- 将原来的SessionAttributes的值设置的Model
- 执行相应注释@ModelAttribute的方法并将值设置到Model
- 处理器注释了了@ModelAttribute的参数同时在SessionAttributes中设置了,而且在mvcCobtainer中没有,则将全部的SessionAttributes中查找并设置进去 -
创建invocableMethod 真正的执行者:继承HandlerMethod,并且可以直接执行,实际请求的处理就是通过它执行的,参数绑定、处理请求、返回值都是这里完成
-
将参数解析组件、返回值处理组件 等组件设置进去:也就是子类实现完成之后的组件,对应之前创建之器声明的哪些保存在成员变量的组件
-
新建mavContainer:保存Model和View,请求参数传递进去
执行
// 调用方法2invokeHandlerMethod():执行请求处理
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 1. 首先创建ServletWebRequest对象
// 在ArgumentResolver解析参数时候的request就是这个对象,处理器需要HttpServletRequest,这是ArgumentResolver就会转换设置
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 2. 初始化3个变量
// 2.1用于参数跟String之间的类型转换,ModelFactory 刷新也会用到它
// 将符合条件注释了@InitBinder的方法找出来,这些方法主要用于处理参数
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 2.2主要是处理Model的,主要包含两个功能,
// 1. 在处理器具体处理之前对Model初始化
// 2. 再处理完成请求后对Model参数更新
//- 将原来的SessionAttributes的值设置的Model
//- 执行相应注释@ModelAttribute的方法并将值设置到Model
//- 处理器注释了了@ModelAttribute的参数同时在SessionAttributes中设置了,而且在mvcCobtainer中没有纸则将全部的SessionAttributes中查找并设置进去
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 2.3继承HandlerMethod,并且可以直接执行,实际请求的处理就是通过它执行的,参数绑定、处理请求、返回值都是这里完成
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 3.将参数解析组件、返回值处理组件 等组件设置进去
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 4. 新建mavContainer:保存Model和View,请求参数传递进去
// 4.1并将相应参数设置进去
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 4.2执行请求
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 4.3请求处理完成完成进行一些后置处理
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
// 4.2执行请求
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1. 执行
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
// 2. 返回值处理
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
// 真正执行
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//1. 准备方法参数
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Arguments: " + Arrays.toString(args));
}
// 2. doInvoke()反射执行,整个执行的核心
return this.doInvoke(args);
}
//1. 获取准备处理器方法参数
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取方法的参数,在HandlerMethod中,子类会自动同步到本类的成员变量
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
// 保存解析出参数的值
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
// 给parameter设置参数名解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 使用resolvers,也就是子类实现的解析器解析
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (this.logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
// 2. 真正反射执行
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(this.getBridgedMethod());
try {
// 真正反射执行
return this.getBridgedMethod().invoke(this.getBean(), args);
} catch (IllegalArgumentException var4) {
this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
throw new IllegalStateException(this.formatInvokeError(text, args), var4);
} catch (InvocationTargetException var5) {
Throwable targetException = var5.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException)targetException;
} else if (targetException instanceof Error) {
throw (Error)targetException;
} else if (targetException instanceof Exception) {
throw (Exception)targetException;
} else {
throw new IllegalStateException(this.formatInvokeError("Invocation failure", args), targetException);
}
}
}
// 4.3请求处理完成完成进行一些后置处理,拿到ModelAndView返回
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
注解@SessionAttributes概述
- 主要用在处理器类上,用于在多个请求之间传递参数,类似于Session的Attribute,但是也不一样,前者只适用暂时的传递,而不是长期的保存,长期应该适用Sesssion的setAttribute()保存
- 主要用法:1、设置了该注解的参数在视图中通过request、session的的getAttribute()获取,2、在后面请求返回的视图中通过session的getAttribute或者Model获取,3、自动将参数设置到后面请求处理器的Model或者@ModelAttribute注解的参数
- 设置方法:1、需要满足在@SessionAttribute注解设置参数名、类型,2、在处理器中将参数设置到Model,之后会自动的有ModelFactory完成更新,使用完毕之后可以调用SessionStatus.setComplete()清除,这对已经存入session的参数。
小结
- SessionAttributesHandler:用来处理@SessionAttributes注释的参数,做一些宏观的事情,如那个Handler可以缓存哪些参数,某个参数再当前的SessionAttribues中是否存在
- SessionAttributeStore:并不是保存数据的容器,而是工具,单个参数的处理操作,可以临时当做缓存处理,容器默认为Session,默认实现DefaultSessionAttributeStore使用ServletWebRequest将参数设置到Session中,具体是在ModelFactory使用
// 主要是针对某个处理器的@SessionAttribute处理
public class SessionAttributesHandler {
// 设置的注解value
private final Set attributeNames = new HashSet();
// 类型
private final Set> attributeTypes = new HashSet();
// 全部的values
private final Set knownAttributeNames = Collections.newSetFromMap(new ConcurrentHashMap(4));
// 操作单个参数的工具,SessionAttributeStore,在session和model之间
private final SessionAttributeStore sessionAttributeStore;
public SessionAttributesHandler(Class> handlerType, SessionAttributeStore sessionAttributeStore) {
Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null");
this.sessionAttributeStore = sessionAttributeStore;
SessionAttributes ann = (SessionAttributes)AnnotatedElementUtils.findMergedAnnotation(handlerType, SessionAttributes.class);
if (ann != null) {
Collections.addAll(this.attributeNames, ann.names());
Collections.addAll(this.attributeTypes, ann.types());
}
this.knownAttributeNames.addAll(this.attributeNames);
}
public boolean hasSessionAttributes() {
return !this.attributeNames.isEmpty() || !this.attributeTypes.isEmpty();
}
public boolean isHandlerSessionAttribute(String attributeName, Class> attributeType) {
Assert.notNull(attributeName, "Attribute name must not be null");
if (!this.attributeNames.contains(attributeName) && !this.attributeTypes.contains(attributeType)) {
return false;
} else {
this.knownAttributeNames.add(attributeName);
return true;
}
}
public void storeAttributes(WebRequest request, Map attributes) {
attributes.forEach((name, value) -> {
if (value != null && this.isHandlerSessionAttribute(name, value.getClass())) {
this.sessionAttributeStore.storeAttribute(request, name, value);
}
});
}
public Map retrieveAttributes(WebRequest request) {
Map attributes = new HashMap();
Iterator var3 = this.knownAttributeNames.iterator();
while(var3.hasNext()) {
String name = (String)var3.next();
Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
if (value != null) {
attributes.put(name, value);
}
}
return attributes;
}
public void cleanupAttributes(WebRequest request) {
Iterator var2 = this.knownAttributeNames.iterator();
while(var2.hasNext()) {
String attributeName = (String)var2.next();
this.sessionAttributeStore.cleanupAttribute(request, attributeName);
}
}
@Nullable
Object retrieveAttribute(WebRequest request, String attributeName) {
return this.sessionAttributeStore.retrieveAttribute(request, attributeName);
}
}
- ModelAndViewContainer:承担整个过程中数据传递工作,除了保存Model和View 外还有一些别的功能,
- 内有属性defaultModel:主要用于封装默认Model数据,就是默认使用Model和ModelAndView时候,ArgumentResolver会传入defaultModel,继承了ModelMap实现了Model接口
- 内有属性redirectModel:主要用于封装重定向之后Model的数据
- 内有属性view:可以是逻辑、实际视图
- 内有属性requestHandler:主要是标志请求是否处理完返回response,是就不在往下处理,直接返回。有@ResposeBody注解的方法或者返回值为Httpentity的都会将该属性设置为true
- …
先看父类HandlerMethod
- 封装Handler和具体处理请求的Method,分别对应bean和method属性,除了这两个还有其他三个属性
- beanFactory:新建HandlerMethod时候传入的Handler是String类型,需要获取Bean
- bridgeMethod:如果Method是bridgeMethod则设置为原有方法
- parameters:请求方法的参数集合,具体元素为MethodParameter类型(内部类),一个对象代表一个方法的请求参数
在父类的基础上
- 增加了方法执行功能
- 相应的增加了参数解析、处理返回值等
- 在父类的基础上加了调用的功能,可以直接调用内部属性method对应的bridgeMethod
- 增加了属性dataBinderFactory(参数解析器使用)、argumentResolvers(解析参数)、paramaterNameDiscover(获取参数名)
MethodParameter 请求方法参数类的成员属性
另外封装参数的内部类是ReturnValueMethodParameter,主要负责方法返回的参数
- 继承HandlerMethodParameter
- 使用的方法都是bridgeMethod,桥方法,为了处理父类泛型的问题,不涉及泛型就是原方法
- 返回值使用的parameterIndex都是-1
子类ServletInvocableHandlerMethod,在父类的基础上增加了3个功能
- 对@ResponseStatus的支持
- 对返回值的处理:HandlerMethodReturnValueHandler类型的成员变量
- 对一部处理结果的处理
概述
- 是用来处理器解析参数的,主要用在上面的InvocableHandlerMethod中,每个Resolver对应一种类型的参数,也就是创建RequestHandelrAdapter时候声明的那些待子类实现的XxxResolver组件的父接口
- 每个实现类对应一种类型的参数,命名大致两种
- XxxMethodArgumentResolver
- XxxMethodProcess:另外包含处理响应类型的返回值
- HandlerMethodArgumentResolverComposite内部可以防多个XxxResolver
解析器介绍
既可以解析参数,也可哟处理返回值
public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
public ModelMethodProcessor() {
}
// 1. 判断如果是Model类型就可以
public boolean supportsParameter(MethodParameter parameter) {
return Model.class.isAssignableFrom(parameter.getParameterType());
}
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
// 2. 直接从 mavContainer 获取 值可能来自FlushMap、SessionAttribute中
return mavContainer.getModel();
}
public boolean supportsReturnType(MethodParameter returnType) {
return Model.class.isAssignableFrom(returnType.getParameterType());
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue != null) {
if (returnValue instanceof Model) {
mavContainer.addAllAttributes(((Model)returnValue).asMap());
} else {
throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}
}
2、解析@PathVariable参数类型的PathVariableMethodArgumentResolver解析器
先看父类AbstractNamedValueMethodArgumentResolver
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
AbstractNamedValueMethodArgumentResolver.NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
Object resolvedName = this.resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");
} else {
// 具体解析参数,是模板方法,在子类实现
Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = this.resolveStringValue(namedValueInfo.defaultValue);
} else if (namedValueInfo.required && !nestedParameter.isOptional()) {
this.handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
arg = this.handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
} else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = this.resolveStringValue(namedValueInfo.defaultValue);
}
// 如果不为空,则用它创建binder并转换解析出的参数
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, (Object)null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
} catch (ConversionNotSupportedException var11) {
throw new MethodArgumentConversionNotSupportedException(arg, var11.getRequiredType(), namedValueInfo.name, parameter, var11.getCause());
} catch (TypeMismatchException var12) {
throw new MethodArgumentTypeMismatchException(arg, var12.getRequiredType(), namedValueInfo.name, parameter, var12.getCause());
}
}
// 对解析出的参数进行后置处理
this.handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
}
首先根据参数类型会去到NamevalueInfo,然后将它传入模板方法resolveName由子类具体实现,最后对解析的结果处理,内部类NamevalueInfo
protected static class NamedValueInfo {
// 参数名
private final String name;
// 是否必须
private final boolean required;
@Nullable
// 默认值
private final String defaultValue;
public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) {
this.name = name;
this.required = required;
this.defaultValue = defaultValue;
}
}
PathVariableMethodArgumentResolver类
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor {
private static final TypeDescriptor STRING_TYPE_DEscriptOR = TypeDescriptor.valueOf(String.class);
public PathVariableMethodArgumentResolver() {
}
public boolean supportsParameter(MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(PathVariable.class)) {
return false;
} else if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
return true;
} else {
PathVariable pathVariable = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
return pathVariable != null && StringUtils.hasText(pathVariable.value());
}
}
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
Assert.state(ann != null, "No PathVariable annotation");
return new PathVariableMethodArgumentResolver.PathVariableNamedValueInfo(ann);
}
// // 具体解析
@Nullable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
Map uriTemplateVars = (Map)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0);
return uriTemplateVars != null ? uriTemplateVars.get(name) : null;
}
protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
throw new MissingPathVariableException(name, parameter);
}
protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) {
String key = View.PATH_VARIABLES;
int scope = 0;
Map pathVars = (Map)request.getAttribute(key, scope);
if (pathVars == null) {
pathVars = new HashMap();
request.setAttribute(key, pathVars, scope);
}
// 存储
((Map)pathVars).put(name, arg);
}
public void contributeMethodArgument(MethodParameter parameter, Object value, UriComponentsBuilder builder, Map uriVariables, ConversionService conversionService) {
if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
String name = ann != null && StringUtils.hasLength(ann.value()) ? ann.value() : parameter.getParameterName();
String formatted = this.formatUriValue(conversionService, new TypeDescriptor(parameter.nestedIfOptional()), value);
// 存储
uriVariables.put(name, formatted);
}
}
// 格式化
@Nullable
protected String formatUriValue(@Nullable ConversionService cs, @Nullable TypeDescriptor sourceType, Object value) {
if (value instanceof String) {
return (String)value;
} else {
return cs != null ? (String)cs.convert(value, sourceType, STRING_TYPE_DEscriptOR) : value.toString();
}
}
private static class PathVariableNamedValueInfo extends NamedValueInfo {
public PathVariableNamedValueInfo(PathVariable annotation) {
super(annotation.name(), annotation.required(), "nttnttnue000ue001ue002nttttn");
}
}
}
涉及方法
- getNamevalueInfo:通过参数类型获得NamedValueInfo,PathVariableNamedValueInfo 根据构造方法使用@PAthVariable注解的value创建了PathVariableNamedValueInfo
- resolveName:具体解析参数,模板方法,可以看出PathVariableMethodArgumentResolver 实现直接从request中获取的HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE属性的值,这个是是在RequestMappingInfoHandlerMapping中的handlerMathch中设置的,也就是在HandlerMapping中根据loouupPath找到处理请求的处理器之后设置的
- resolveDefaultValue:设置默认值
- handlerMissingValue:参数必须存在并且没有默认值,就会调用该模板方法
- handlerResolverValue:处理解析出的参数值的模板方法,PathVariableMethodArgumentResolver 实现将解析的参数设置到request中
作用在ServletInvocableHandlerMethod中,作用是处理处理器执行后的返回值,主要由三个功能
- 将对应的参数添加到Model
- 设置view
- 如果请求已经处理完成ModelAndViewContainer的requestHandled为true
原理和上述类似,主要一个包括判断支持、一个用于具体处理返回值,有很多实现子类
3、总结- HandlerAdapter主要的四个实现类,RequestMappingHandlerAdapter较为复杂,其他简单,应该是SpringMVC最复杂的组件
- 主要流程三步骤:将诶西参数、执行请求、处理返回值
- 解析参数的过程参数来源有:Model、request,前者通过FlashMapManager和ModelFactory管理
- 执行请求是HandlerMethod的子类ServletInvocableHandlerMethod,实际执行的时InvocableHandlerMethod
- 返回值有HandlerMethodReturnValueHandler处理,不同的返回值对应不同的实现子类
主要作用是根据视图名和Locale解析出视图,解析过程主要做两件事
- 解析出使用的模板
- 解析出视图的类型
主要的实现类
- ContentNegotiatingViewResolver主要作用是在别的解析器解析的结果加上Content-Type,对视图的解析并不是自己完成的,而是使用封装的ViewResolver来进行的,整个过程:首先遍历所封装的ViewResolver具体解析视图,可能会有多个结果,然后在使用request获取的Content-Type,最后对这两个结果进行匹配查找最优的视图
- AbstractCachingViewResolver系列:提供了统一的缓存功能,当视图解析过一次就被缓存起来,直到缓存被删除前视图的解析都会从缓存中获取
主要作用是解析请求处理过程中产生的异常
- AbstractHandlerExceptionResolver:模板类和子类ExceptionHandlerExceptionResolver一起完成@ExceptionHandler注解方法进行异常解析
- DefaultHandlerExceptionResolver:按照不同类型分别对异常解析
- ResponseStatusExceptionResolver:解析有@ResponseStatus注解类型的异常
- SimpleMappingExceptionResolver:通过配置的异常和view的对应关系来解析异常
解析过程主要包括:给ModelAndView设置相应内容、设置response的相关属性,当然可以有一些辅助功能如记录日志
@Override
@Nullable
public ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
// 判断当前ExceptionResolver是否可以解析所传入处理器所抛出的异常
if (shouldApplyTo(request, handler)) {
prepareResponse(ex, response);
// 模板方法
ModelAndView result = doResolveException(request, response, handler, ex);
if (result != null) {
// Print debug message when warn logger is not enabled.
if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
}
// Explicitly configured warn logger in logException method.
logException(ex, request);
}
return result;
}
else {
return null;
}
}
六、MultipartResolver
用于处理上传请求,有两个实现类,
-
StandardServletMultipartResolver (使用Servlet3.0的标准上传格式)
-
CommonsMultipartResolver(后者使用Apache的commons-fileupload)
配置的参数
SpringMVC的处理过程
下面具体分析
0、SpringMVC的创建 1、发送请求(Servlet容器) 2、ServletRequest转为HttpServletrequest(HttpSetvlet) 3、请求初步经service()处理(frameworkServlet、HttpServlet之间) 4、请求汇总到processRequest(frameworkServlet) 5、doService调用doDispatch内部调用getHandler(DispatchServlet) 6、根据请求寻找Handler及其处理方法(RequestMappingHandlerMapping) 7、找到处理方法之后将请求参数的设置request里面(RequestMappingInfoHandlerMapping) 8、根据Handler找HandlerAdapter之后处理请求(DispatchServlet) 9、HandlerAdapter调用Handler处理请求(RequestMappingHandlerAdapter)- HandlerAdapter的handler()方法是模板方法,进而调用子类RequestMappingHandlerAdapter的getHandlerInternal()方法



