以前阅读过DispatcherServlet的doService(HttpServletRequest, HttpServletResponse)和doDispatch(HttpServletRequest, HttpServletResponse)的源码,后来过了一段时间后又忘了,所以把这次阅读的内容写一篇博客,记录下来。
首先看doService(HttpServletRequest, HttpServletResponse)方法中的源码;
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
在该方法中,大部分都是设置request的属性值,方便后面的方法获取相应的对象,我们可能会需要获取的属性名为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE的HttpServletRequest属性值,它是当前mvc的WebApplicationContext对象。下面看doDispatch(HttpServletRequest, HttpServletResponse)方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否Multipart请求(文件上传),如果是,调用MultipartResolver.resolveMultipart(HttpServletRequest)解析Multipart资源,返回一个适配类MultipartHttpServletRequest,否则返回参数中的request。
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
解析文件上传
在这个方法中去调用checkMultipart(HttpServletRequest),再去调用multipartResolver.resolveMultipart(request)解析Multipart资源,实际上这个方法返回了一个MultipartHttpServletRequest接口的实现对象,MultipartHttpServletRequest接口继承了HttpServletRequest和MultipartRequest,获取文件的操作都在MultipartRequest中定义。protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) { logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " + "this typically results from an additional MultipartFilter in web.xml"); } else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) { logger.debug("Multipart resolution failed for current request before - " + "skipping re-resolution for undisturbed error rendering"); } else { //解析 return this.multipartResolver.resolveMultipart(request); } } // If not returned before: return original request. return request; }
- 其中MultipartResolver默认有两个实现类,分别是CommonsMultipartResolver和StandardServletMultipartResolver,要想了解具体的实现可以去看这两个类的源码。
获取Handler
解析multipart资源后,就是要找到hander对象,以及拦截器链。调用HandlerMapping#getHandler(HttpServletRequest request)方法去查找,返回HandlerExecutionChain对象。在xml中使用\会自动加载RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,HandlerAdapter,HandlerMethodArgumentResolver,HttpMessageConverter,以及其它相关类,如果有兴趣了解的,可以去看类org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser的源码。
HandlerMapping有几个子类是在初始化时默认加载的:
RequestMappingHandlerMapping
扫描@Controller标注的类中,获取@RequestMapping注解的类实例和方法,创建RequestMappingInfo(请求映射信息)对象。BeanNameUrlHandlerMapping
这是Dispatcher Servlet的默认的HandlerMapping,所以在应用上下文配置文件中简单地用“Url样式”来定义一个控制器Bean的名字,就可以告诉Dispatcher Servlet什么样式的请求应该由哪个控制器去处理,而不用显式地定义一个HandlerMapping。
例:若控制器ListCoursesController的URL样式是“listCourses.go”, 示例如下:
<bean name="/listCourses.go" class="com.w3cs.vlar.ListCoursesController">
<property name="couseService">
<ref bean="courceService"/>
</property>
</bean>
```
在doDispatch(HttpServletRequest, HttpServletResponse)方法中去遍历handlerMappings字段,它是一个List<HandlerMapping>对象,调用HandlerMapping#getHandler(HttpServletRequest),该方法的代码如下:
```java
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取请求对应的HandlerMethod对象。
Object handler = getHandlerInternal(request);
if (handler == null) {
//如果没有找到,获取默认的handlerMethod对象
handler = getDefaultHandler();
}
//如果没有,返回null
if (handler == null) {
return null;
}
//获取Hander对象
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//获取Handler对象执行链,把匹配的拦截器加入到执行链中。
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//通过header中的Origin字段防cors攻击
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
```
获取请求对应的HandlerMethod对象的getHandlerInternal(HttpServletRequest)最终会进入到lookupHandlerMethod(Strin, HttpServletRequest)方法中。
通过requestUri查找RequestMappingInfo对象。如果没有找到,将所有的RequestMappingInfo对象都加入到列表中。然后按@RequestMapping匹配度进行排序,取匹配度最高的。
```java
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
//排序
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
```
RequestMapping匹配内容的排序规则如下:
如果是HEAD提交方式,先去比较提交方式,比较GET和HEAD,GET优先。
比较path,比较path和requestUri的匹配度
比较参数 params 匹配数量,多排前面
比较请求匹配数量,多排前面
比较request Content-Type的内容,匹配上的排前面
比较request Accept的内容,匹配上的排前面
比较请求方式,匹配上的排前面
最后一种是比较自定义的匹配条件。
```java
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
int result;
// Automatic vs explicit HTTP HEAD mapping
if (HttpMethod.HEAD.matches(request.getMethod())) {
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
if (result != 0) {
return result;
}
}
result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
if (result != 0) {
return result;
}
result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
if (result != 0) {
return result;
}
result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
if (result != 0) {
return result;
}
result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
if (result != 0) {
return result;
}
result = this.producesCondition.compareTo(other.getProducesCondition(), request);
if (result != 0) {
return result;
}
// Implicit (no method) vs explicit HTTP method mappings
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
if (result != 0) {
return result;
}
result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
if (result != 0) {
return result;
}
return 0;
}
```
这是获取Handler执行链的方法,可以看到里面是去匹配拦截器指定拦截的路径,如果匹配上,就加入执行链中。
```java
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
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. 获取HandlerAdapter
执行完上面的代码后取得HandlerMethod,然后再去获取HandlerAdapter对象,HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求进行处理。当handlerMapping获取到执行请求的HandlerMetho时,DispatcherServlte会根据HandlerMethod对应的类型来调用相应的HandlerAdapter来进行处理。
DispatcherServlte会根据配置文件信息注册HandlerAdapter,如果在配置文件中没有配置,那么DispatcherServlte会获取HandlerAdapter的默认配置,如果是读取默认配置的话,DispatcherServlte会读取DispatcherServlte.properties文件,该文件中配置了三种HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter。DispatcherServlte会将这三个HandlerAdapter对象存储到它的handlerAdapters这个集合属性中,这样就完成了HandlerAdapter的注册。
几种适配器对应的处理器以及这些处理器的作用\
1. AnnotationMethodHandlerAdapter主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器。在spring3.2之后改用了RequestMappingHandlerAdapter,RequestMappingHandlerAdapter是在解析\<mvc:annotation-driven>时由org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser自动加载的。
2. HttpRequestHandlerAdapter主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。
3.SimpleControllerHandlerAdapter是Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController,那么自己写的这些Controller就会由SimpleControllerHandlerAdapter来适配。
4.SimpleServletHandlerAdapter是Servlet处理适配器,适配实现了Servlet接口或Servlet的子类的处理器,我们不仅可以在web.xml里面配置Servlet,其实也可以用SpringMVC来配置Servlet,不过这个适配器很少用到,而且SpringMVC默认的适配器没有他,默认的是前面的三种。
获取HandlerAdapter的代码如下:
```java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
<div class="se-preview-section-delimiter"></div>
方法内部运行一个for循环,然后通过supports(Object)方法去判断是否支持,如果支持,就返回这个HandlerAdapter。下面列出RequestMappingHandlerAdapter#supports(Object)的代码。
RequestMappingHandlerAdapter是继承AbstractHandlerMethodAdapter,但是AbstractHandlerMethodAdapter中有一个抽象方法supportsInternal(HandlerMethod)是由子类去实现的。
AbstractHandlerMethodAdapter#supports(Object)
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
<div class="se-preview-section-delimiter"></div>
RequestMappingHandlerAdapter#supportsInternal(HandlerMethod)
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
<div class="se-preview-section-delimiter"></div>
RequestMappingHandlerAdapter#supportsInternal(HandlerMethod)方法没有做任何其它的判断了,直接返回true。这就是我们通过@Controller注解定义的Action查找HandlerAdapter的逻辑。
4. 执行拦截器的preHandle(HttpServletRequest, HttpServletResponse, Object)方法
doDispatcher()方法中会执行HandlerExecutionChain#applyPreHandle(HttpServletRequest, HttpServletResponse)方法,它类似于责任链,如果其中有一个拦发器返回false,表示请求被拦截,然后执行拦截器的afterCompletion()方法。再结束doDispatch方法。
doDispatch(HttpServletRequest, HttpServletResponse) 方法中的代码段
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
<div class="se-preview-section-delimiter"></div>
HandlerExecutionChain#applyPreHandle(HttpServletRequest, HttpServletResponse)
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
//如果失败,直接调用拦截器的afterCompletion()方法
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
<div class="se-preview-section-delimiter"></div>
5. 执行HandlerAdapter
这里以RequestMappingHandlerAdapter为例,了解一下HandlerAdapter处理请求的一个过程,以及直接返回json是如何处理的。
调用RequestMappingHandlerAdapter#handler(HttpServletRequest, HttpServletResponse, Object)方法后,会执行到invokeHandlerMethod(HttpServletRequest,HttpServletResponse, HandlerMethod),在这个方法会先组装模型,然后执行invocableMethod.invokeAndHandle(webRequest, mavContainer)
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
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();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
<div class="se-preview-section-delimiter"></div>
ServletInvocableHandlerMethod#invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object…)
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//解析参数,执行HanderMethod
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//处理返回结果(比如返回json)
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
<div class="se-preview-section-delimiter"></div>
先来看看invokeForRequest()方法是怎么解析参数,然后执行Controller里面的方法的。
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取方法参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
//执行method方法,获得返回值
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
<div class="se-preview-section-delimiter"></div>
上面的方法逻辑是先获取方法参数值,然后执行Controller中的方法,获得返回值。
先看获取方法参数值的流程。
HandlerMethodArgumentResolverComposite
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//获取方法参数解析器
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
//解析参数
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
//获取方法参数解析器的方法
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
<div class="se-preview-section-delimiter"></div>
HandlerMethodArgumentResolver是处理器方法参数解析器,它只有两个方法,判断是否支持解析指定的参数,和解析参数。看源码:
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
<div class="se-preview-section-delimiter"></div>
- HandlerMethodArgumentResolver实现了很多方案,因此也有不少子类:
RequestParamMethodArgumentResolver
支持两种场景。一种是含@RequestParam注解的参数,另一种就是简单类型,如Integer、String、Date、URI, URL,Locale等RequestParamMapMethodArgumentResolver
用来获取所有的header信息。
参数类型可以是普通的Map类型,也可以是MultiValueMap或者进一步的Http请求参数,他们与普通Map类型的区别是他们对value值后者们是以List形式存放,前者是以String形式存放。RequestHeaderMethodArgumentResolver
主要用来处理含有@RequestHeader注解的参数,但同时该参数又不是Map类型。使用场景:
@RequestMapping(value="/requestHeader",method=RequestMethod.GET) public Map<String,Object> testrequestHeader(@RequestHeader String Accept){ }
RequestHeaderMapMethodArgumentResolver
用来获取所有的header信息。
参数类型可以是普通的Map类型,也可以是MultiValueMap或者进一步的HttpHeaders,他们与普通Map类型的区别是他们对value值后者们是以List形式存放,前者是以String形式存放。使用场景:
@RequestMapping(value="/requestHeader",method=RequestMethod.GET) public Map<String,Object> testrequestHeader(@RequestHeader Map<String,Object> map1){ } @RequestMapping(value="/requestHeader1",method=RequestMethod.GET) public Map<String,Object> testrequestHeader2(@RequestHeader MultiValueMap<String,Object> map1){ }
ServletCookieValueMethodArgumentResolver
主要处理处理器方法参数中带有@CookieValue的解析工作。
它的验证代码在AbstractCookieValueMethodArgumentResolver中public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(CookieValue.class); }
判断是否支持非常简单,解析代码也是一样的。
protected Object resolveName(String cookieName, MethodParameter parameter, NativeWebRequest webRequest) throws Exception { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName); if (Cookie.class.isAssignableFrom(parameter.getNestedParameterType())) { return cookieValue; } else if (cookieValue != null) { return this.urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue()); } else { return null; } }
PathVariableMethodArgumentResolver
主要针对含有@PathVariable的参数。必须要指定@PathVariable的值,即这个ArgumentResolver只能获取一个uri变量,要想获取多个则要使用PathVariableMapMethodArgumentResolver。
public boolean supportsParameter(MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(PathVariable.class)) {
return false;
}
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
return StringUtils.hasText(paramName);
}
return true;
}
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
}
<div class="se-preview-section-delimiter"></div>
- PathVariableMapMethodArgumentResolver
它要求必须含有@PathVariable注解,并且必须是Map类型,并且@PathVariable注解的value没有值。
public boolean supportsParameter(MethodParameter parameter) {
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
return (ann != null && (Map.class.isAssignableFrom(parameter.getParameterType()))
&& !StringUtils.hasText(ann.value()));
}
/**
* Return a Map with all URI template variables or an empty map.
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
@SuppressWarnings("unchecked")
Map<String, String> uriTemplateVars =
(Map<String, String>) webRequest.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
if (!CollectionUtils.isEmpty(uriTemplateVars)) {
return new LinkedHashMap<String, String>(uriTemplateVars);
}
else {
return Collections.emptyMap();
}
<div class="se-preview-section-delimiter"></div>
同时我们可以从PathVariableMapMethodArgumentResolver和PathVariableMethodArgumentResolver的源码中看出,他们的取值都是从request的属性上进行获取的webRequest.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);也就是说,在解析完@RequestMapping匹配工作后,便将这些参数设置进request的属性上,属性名为HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE。
- SessionAttributeMethodArgumentResolver
解析@SessionAttribute标注的参数。 - RequestAttributeMethodArgumentResolver
解析@RequestAttribute标注的参数。 - MatrixVariableMethodArgumentResolver
解析@MatrixVariable标注的参数。 - MatrixVariableMapMethodArgumentResolver
解析@MatrixVariable标注的参数。
下面我们以RequestParamMethodArgumentResolver为例,从中了解HandlerMethodArgumentResolver的处理过程。
在执行解析的方法时,会调用到父类AbstractNamedValueMethodArgumentResolver#resolveArgument(MethodParameter, ModelAndViewContainer,NativeWebRequest, WebDataBinderFactory)方法,在这个方法中会去调用一个抽象方法resolveName(String, MethodParameter, NativeWebRequest),这个方法是由子类去实现的。
AbstractNamedValueMethodArgumentResolver
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
Object resolvedName = resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//抽象方法,由子类去实现
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
//会进一步做数据转换工作,这个步骤以后有时间再了解。
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
}
catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
protected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request)
throws Exception;
protected void handleResolvedValue(Object arg, String name, MethodParameter parameter,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
}
<div class="se-preview-section-delimiter"></div>
RequestParamMethodArgumentResolver#resolveName(String, MethodParameter, NativeWebRequest)
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
return mpArg;
}
Object arg = null;
if (multipartRequest != null) {
//获取文件
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
//获取参数值
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
return arg;
}
<div class="se-preview-section-delimiter"></div>
上面的代码是处理器方法参数获取和解析的过程,通过这个过程,拿到最终的参数,调用处理器方法。这一步很简单了,就是通过java反射实现的了。java.lang.reflect.Method#invode(Object, Object…)。
InvocableHandlerMethod
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.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 {
String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
throw new IllegalStateException(msg, targetException);
}
}
}
<div class="se-preview-section-delimiter"></div>
拿到返回值之后,就调用HandlerMethodReturnValueHandler接口的handleReturnValue(Object, MethodParameter, ModelAndViewContainer, NativeWebRequest)方法去处理返回的数据了。下面给出HandlerMethodReturnValueHandler接口的实现类的源码。
HandlerMethodReturnValueHandlerComposite
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//获取返回值处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//处理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
//获取返回值处理器
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
<div class="se-preview-section-delimiter"></div>
现在返回json数据的应用接口很广,这里就给出输入json和渲染页面的处理器方法返回值处理器(HandlerMethodReturnValueHandler)。
RequestResponseBodyMethodProcessor
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//这里设置了请求已被处理,在上层方法中将不会返回ModelAndView对象了。
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
//将找到返回值转换
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
<div class="se-preview-section-delimiter"></div>
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object outputValue;
Class<?> valueType;
Type declaredType;
if (value instanceof CharSequence) {
outputValue = value.toString();
valueType = String.class;
declaredType = String.class;
}
else {
outputValue = value;
valueType = getReturnValueType(outputValue, returnType);
declaredType = getGenericType(returnType);
}
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
if (outputValue != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
}
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
for (MediaType requestedType : requestedMediaTypes) {
for (MediaType producibleType : producibleMediaTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (compatibleMediaTypes.isEmpty()) {
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
return;
}
List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
MediaType.sortBySpecificityAndQuality(mediaTypes);
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter) {
if (((GenericHttpMessageConverter) messageConverter).canWrite(
declaredType, valueType, selectedMediaType)) {
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
((GenericHttpMessageConverter) messageConverter).write(
outputValue, declaredType, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
"\" using [" + messageConverter + "]");
}
}
return;
}
}
//判断是否可以输入返回值类型和响应的MediaType
else if (messageConverter.canWrite(valueType, selectedMediaType)) {
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
//输出数据,下面给出代码。
((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
"\" using [" + messageConverter + "]");
}
}
return;
}
}
}
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
<div class="se-preview-section-delimiter"></div>
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
final HttpHeaders headers = outputMessage.getHeaders();
//设置响应头信息
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage =
(StreamingHttpOutputMessage) outputMessage;
streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
@Override
public void writeTo(final OutputStream outputStream) throws IOException {
//输出数据
writeInternal(t, new HttpOutputMessage() {
@Override
public OutputStream getBody() throws IOException {
return outputStream;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
});
}
});
}
else {
//输出数据
writeInternal(t, outputMessage);
outputMessage.getBody().flush();
}
}
<div class="se-preview-section-delimiter"></div>
输出json的HttpMessageConverter的输出数据方法
protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
String json = "";
if(customPropertyPreFilter != null){
json = Json.toJSONStringWithCustom(obj, customPropertyPreFilter, serializerFeature);
}else{
json = Json.toJSONString(obj, serializerFeature);
}
LOG.debug(json);
OutputStream out = outputMessage.getBody();
byte[] bytes = json.getBytes(charset);
out.write(bytes);
}
<div class="se-preview-section-delimiter"></div>
数据渲染的处理器方法返回值处理器(HandlerMethodReturnValueHandler)。
ModelAndViewMethodReturnValueHandler
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
ModelAndView mav = (ModelAndView) returnValue;
if (mav.isReference()) {
String viewName = mav.getViewName();
mavContainer.setViewName(viewName);
if (viewName != null && isRedirectViewName(viewName)) {
//设置跳转标记
mavContainer.setRedirectModelScenario(true);
}
}
else {
View view = mav.getView();
mavContainer.setView(view);
if (view instanceof SmartView) {
if (((SmartView) view).isRedirectView()) {
//设置跳转标记
mavContainer.setRedirectModelScenario(true);
}
}
}
mavContainer.setStatus(mav.getStatus());
mavContainer.addAllAttributes(mav.getModel());
}
<div class="se-preview-section-delimiter"></div>
6. 执行拦截器的postHandle(HttpServletRequest, HttpServletResponse, Object, ModelAndView)方法
执行拦截器的这个方法是要正常运行完HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)方法,如果中间抛出异常或发生错误(error),这个方法不被执行,但是拦截器的afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)方法依然会执行。
需要注意的是如果HandlerMethod对应的的Controller方法中定义了@ResponseBody的话,ModelAndView将等于null.
7. 处理异常和渲染页面
到这一步执行的方法是processDispatchResult(HttpServletRequest, HttpServletResponse,HandlerExecutionChain, ModelAndView, Exception)
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
//判断是否发生异常
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//处理Handler抛出的异常
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//数据渲染
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
//执行拦截器的afterCompletion()方法。
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
<div class="se-preview-section-delimiter"></div>
- 异常处理
在这个方法中会先去判断在HandlerAdapter#handler(HttpServletRequest, HttpServletResponse)方法中是否出现异常或错误,如果有出现,则调用xml配置文件中的HandlerExceptionResolver#resolveException(HttpServletRequest, HttpServletResponse, Object, Exception)方法,这个方法会返回一个ModelAndView对象,在配置文件中可以配多个HandlerExceptionResolver,如果HandlerExceptionResolver#resolveException(HttpServletRequest, HttpServletResponse, Object, Exception)方法返回值等null,将会继续执行下一个HandlerExceptionResolver#resolveException(HttpServletRequest, HttpServletResponse, Object, Exception)方法。所以在配置HandlerExceptionResolver时也需要注意。
代码如下:
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
if (!exMv.hasView()) {
exMv.setViewName(getDefaultViewName(request));
}
if (logger.isDebugEnabled()) {
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
<div class="se-preview-section-delimiter"></div>
- 视图渲染
如果ModelAndView对象不等于null,会通过ViewResolver对象解析出相应的View对象,然后由View对象去渲染页面。
DispatcherServlet
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
//是否引用,mv.isReference()的代码如下
/*public boolean isReference() {
return (this.view instanceof String);
}*/
if (mv.isReference()) {
// We need to resolve the view name.
//调用ViewResolver解析视图
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//渲染
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
<div class="se-preview-section-delimiter"></div>
ViewResolver可以在xml配置文件中配置多个,一般ViewResolver的实现类都实现Ordered接口,所以可以通过Ordered排序,只要ViewResolver解析到View,就返回View去渲染。
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
<div class="se-preview-section-delimiter"></div>
以FreeMarkerViewResolver为例,创建和加载View对象的方法分别在父类AbstractCachingViewResolver和UrlBasedViewResolver中,由FreeMarkerView去检查模版是否存在,如果不存在返回null,如果存在就返回,然后渲染页面。
UrlBasedViewResolver
protected View createView(String viewName, Locale locale) throws Exception {
// If this resolver is not supposed to handle the given view,
// return null to pass on to the next resolver in the chain.
if (!canHandle(viewName, locale)) {
return null;
}
// Check for special "redirect:" prefix.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
view.setHosts(getRedirectHosts());
return applyLifecycleMethods(viewName, view);
}
// Check for special "forward:" prefix.
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
return new InternalResourceView(forwardUrl);
}
// Else fall back to superclass implementation: calling loadView.
//调用父类的方法
return super.createView(viewName, locale);
}
//实现父类的抽象方法
protected View loadView(String viewName, Locale locale) throws Exception {
AbstractUrlBasedView view = buildView(viewName);
View result = applyLifecycleMethods(viewName, view);
return (view.checkResource(locale) ? result : null);
}
//创建View
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
view.setUrl(getPrefix() + viewName + getSuffix());
String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
}
view.setRequestContextAttribute(getRequestContextAttribute());
view.setAttributesMap(getAttributesMap());
Boolean exposePathVariables = getExposePathVariables();
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
}
return view;
}
//设置View的Class
public void setViewClass(Class<?> viewClass) {
if (viewClass == null || !requiredViewClass().isAssignableFrom(viewClass)) {
throw new IllegalArgumentException(
"Given view class [" + (viewClass != null ? viewClass.getName() : null) +
"] is not of type [" + requiredViewClass().getName() + "]");
}
this.viewClass = viewClass;
}
//生成View对象时用到
protected Class<?> getViewClass() {
return this.viewClass;
}
protected Class<?> requiredViewClass() {
return AbstractUrlBasedView.class;
}
<div class="se-preview-section-delimiter"></div>
AbstractCachingViewResolver
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (!isCache()) {
return createView(viewName, locale);
}
else {
Object cacheKey = getCacheKey(viewName, locale);
View view = this.viewAccessCache.get(cacheKey);
if (view == null) {
synchronized (this.viewCreationCache) {
view = this.viewCreationCache.get(cacheKey);
if (view == null) {
// Ask the subclass to create the View object.
view = createView(viewName, locale);
if (view == null && this.cacheUnresolved) {
view = UNRESOLVED_VIEW;
}
if (view != null) {
this.viewAccessCache.put(cacheKey, view);
this.viewCreationCache.put(cacheKey, view);
if (logger.isTraceEnabled()) {
logger.trace("Cached view [" + cacheKey + "]");
}
}
}
}
}
return (view != UNRESOLVED_VIEW ? view : null);
}
}
protected View createView(String viewName, Locale locale) throws Exception {
//调用子类的加载view的方法
return loadView(viewName, locale);
}
//抽象方法
protected abstract View loadView(String viewName, Locale locale) throws Exception;
<div class="se-preview-section-delimiter"></div>
FreeMarkerViewResolver
public class FreeMarkerViewResolver extends AbstractTemplateViewResolver {
/**
* Sets the default {@link #setViewClass view class} to {@link #requiredViewClass}:
* by default {@link FreeMarkerView}.
*/
public FreeMarkerViewResolver() {
//设置创建的View对象的Class
setViewClass(requiredViewClass());
}
/**
* A convenience constructor that allows for specifying {@link #setPrefix prefix}
* and {@link #setSuffix suffix} as constructor arguments.
* @param prefix the prefix that gets prepended to view names when building a URL
* @param suffix the suffix that gets appended to view names when building a URL
* @since 4.3
*/
public FreeMarkerViewResolver(String prefix, String suffix) {
this();
setPrefix(prefix);
setSuffix(suffix);
}
/**
* Requires {@link FreeMarkerView}.
*/
@Override
protected Class<?> requiredViewClass() {
return FreeMarkerView.class;
}
}
<div class="se-preview-section-delimiter"></div>
FreeMarkerView
public boolean checkResource(Locale locale) throws Exception {
try {
// Check that we can get the template, even if we might subsequently get it again.
getTemplate(getUrl(), locale);
return true;
}
catch (FileNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("No FreeMarker view found for URL: " + getUrl());
}
return false;
}
catch (ParseException ex) {
throw new ApplicationContextException(
"Failed to parse FreeMarker template for URL [" + getUrl() + "]", ex);
}
catch (IOException ex) {
throw new ApplicationContextException(
"Could not load FreeMarker template for URL [" + getUrl() + "]", ex);
}
}
//获取模版,如果模不存在,会抛异常。
protected Template getTemplate(String name, Locale locale) throws IOException {
return (getEncoding() != null ?
getConfiguration().getTemplate(name, locale, getEncoding()) :
getConfiguration().getTemplate(name, locale));
}
- 执行拦截器的afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)方法
在最后将会执行拦截器的afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)方法
这里要注意,如果拦截器的afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)方法中有抛异常,那么拦截器的afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)方法将会被执行两遍。
8. 执行拦截器的afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)方法
拦截器的这个方法不管是否抛出异常都会被执行,如果抛出异常,方法参数中的Exception将不为空。所以如果要在拦截器中释放资源,不要拦截器的postHandle(HttpServletRequest, HttpServletResponse, Object, ModelAndView)中释放,应该在这个方法中释放。
https://blog.csdn.net/mr_rain/article/details/68928711
@RequerstMapping使用示例 http://blog.csdn.net/kobejayandy/article/details/12690041
HandlerMethodArgumentResolver介绍 http://blog.csdn.net/qq_34120041/article/details/53606561