上一节,已经分析了获取执行链HandlerExecutionChain的过程,接下来继续分析DispatcherServlet的doDispatch方法下面要执行的内容。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
从获取处理器的适配器接着分析,为什么还需要这个适配器呢?到底需要适配什么内容?这个问题分析完成后再回答,现在进入这个方法中,很显然是从所有的适配器中找到通过支持此handler处理的。
/**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
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");
}
在上面的代码中注意的地方是this.handlerAdapters的内容是怎么来的?ha.supports(handler)这个方法判断了什么?先来看看this.handlerAdapters的初始化(在DispatcherServlet类中)
/**
* Initialize the HandlerAdapters used by this class.
* If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
* we default to SimpleControllerHandlerAdapter.
*/
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
//首先是一个变量(默认为true,但在web.xml中通过init-param可以设置成false)
//意思是检测所有的handlerAdapters
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
//如果设置成了false,那么尝试获取名称为“handlerAdapter”的bean实例
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
//如果都没有,那么就加载默认配置的适配器(在DispatcherServlet.properties文件中)
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
总之,上面的初始化过程是,先判断是否需要检测加载上下文中所有的适配器(默认),如果不是则尝试加载名称 是“handlerAdapter”的适配器。如果都没有,则加载默认配置的适配器。
org.springframework.web.servlet.HandlerAdapter=\
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
可以看到它配置了三种适配器,分别为:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,各自的作用是:
所以,在这里我们就可以理解为什么需要适配器,主要是spring中使用的handler之间可以没有特殊的关系,但为了达到统一处理的目的,spring提供了不同handler的适配器去适配不同类型的handler处理器,其实除了上述的三种适配器还有SimpleServletHandlerAdapter、RequestMappingHandlerAdapter与上面的SimpleControllerHandlerAdapter原理大同小异。这样使得handler的实现更加多样化,与只能实现handler接口的方法相比也更加灵活。
分析完了Adapter适配器,接下来看看ha.supports(handler)是如何判断的,它是在handlerAdapter子类中实现的,不同的子类实现不太一样,又大致相同
HttpRequestHandlerAdapter中的实现
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
SimpleControllerHandlerAdapter
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
AnnotationMethodHandlerAdapter
@Override
public boolean supports(Object handler) {
return getMethodResolver(handler).hasHandlerMethods();
}
RequestMappingHandlerAdapter这个与之前的有所区别,上面的都是直接实现了HandlerAdapter接口,而此类是继承了AbstractHandlerMethodAdapter。它主要是判断当前handler对象是否是HandlerMethod类的实例和是否支持当前handlerMethod
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
* @param handler the handler instance to check
* @return whether or not this adapter can adapt the given handler
*/
@Override
public final boolean supports(Object handler) {
//supportsInternal总是返回true
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
到此我们已经获取到了处理器的适配器,接着回到DispatcherServlet的doDispatch方法,看下面一段代码。先判断是GET请求,再判断重新getLastModified的时间戳是否新于上一次请求的时间,如果是最新的则说明请求的内容已经修改,继续往下执行,如果没有修改,则直接返回一个304的状态码,不再往下执行,浏览器拿304码后,直接拿缓存的数据展示。
// 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;
}
}
接下来,就是执行执行链中的拦截器的preHandler方法,如果任何一下拦截器的此方法返回了false,就会调用triggerAfterCompletion进行资源清理,此方法也是遍历所有拦截器调用拦截器的afterCompletion()方法,然后返回false,doDispatch方法不会再往下执行。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
再往下,这才是重点,就是适配器执行handler方法,返回ModelAndView,上面也说了不同的handler处理器对应不同的适配器,所以此方法也肯定是由各子类去实现的
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
在这里我们主要是看AbstractHandlerMethodAdapter
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
protected abstract ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
再进入handleInternal,就来到了RequestMappingHandlerAdapter类的handleInternal方法中,我们来看看这个方法做了什么
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
/**
检查请求,调用它父类WebContentGenerator中的checkRequest()方法,判断支持的请求方式
是否包含当前请求的方式,如果supportedMethods不为空且不支持当前请求方式,
会抛出著名的HttpRequestMetohdNotSupportedException。
如果需要session且从当前请求获得不到session,
同样抛出HttpSessionRequiredException异常
*/
checkRequest(request);
/**
判断headlerMethod上是否有@SessionAttributes的注解,如果有
则在response上设置Cache-Control
*/
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
//如果没有,则预处理response,判断cacheControl是否为空
//如果不空则设置,如果为空则清空response的cacheControl
prepareResponse(response);
}
// Execute invokeHandlerMethod in synchronized block if required.
//判断是否需要同步机制来执行invokeHandlerMethod
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandlerMethod(request, response, handlerMethod);
}
}
}
//如果不需要则直接执行method
return invokeHandlerMethod(request, response, handlerMethod);
}
进入到RequestMappingHandlerAdapter类的invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//封装一个RequestAttribute,方便取各参数
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//获取一个绑定工厂类,主要用于创建WebDataBinder对象
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);
}
上面第二步获取WebDataBinderFactory,它的作用是创建WebDataBinder对象。我们都知道客户端无论什么类型的参数,最终都是以字节的形式传给服务端,然后由request.getParameter方法以字符串的形式取出来。这样就需要有一个转换类把这个字符串类型转给我们需要的类型,比如:2019-02-28转换成Date类型等等。WebDataBinder对象就是我们需要的转换工具,它不需要我们去创建,我们只需要使用类似 binder.registerCustomEditor(Long.class, new CustomNumberEditor(Long.class, true))的操作向它注册相应的PropertyEditor(最常见的做法实现WebBindingInitializer接口)。PropertyEditor调用它的void setAsText(String text)方法实现数据转换的过程可以将字符串转换成真正的数据类型,这个是sun包中的类,比如:BooleanPropertyEditor,LongPropertyEditor等等。除了使用PropertyEditor转换外,我们还可以使用org.springframework.core.convert.converter.Converter,并且把它注册到org.springframework.context.support.ConversionServiceFactoryBean中来实现类型的转换。
扯远了,我们再回到ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);方法
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class> handlerType = handlerMethod.getBeanType();
Set methods = this.initBinderCache.get(handlerType);
if (methods == null) {
methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
List initBinderMethods = new ArrayList();
// Global methods first
//首先遍历所有@ControllerAdvice注解的类,从这些类中找到@InitBinder的方法
//封装成InitBinderMethod对象加入到list中
for (Entry> entry : this.initBinderAdviceCache .entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
}
//说明可以有多个@InitBinder
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
return createDataBinderFactory(initBinderMethods);
}
先是从initBinderCache中获取,如果没有取到,就重新使用查找器找,INIT_BINDER_METHODS这是一个Filter,可以看到在当前类中找@InitBinder注解的方法,再放到缓存中
public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() {
@Override
public boolean matches(Method method) {
return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
}
};
从这里可以看出所创建的WebDataBinderFactory,其实是ServletRequestDataBinderFactory
protected InitBinderDataBinderFactory createDataBinderFactory(List binderMethods)
throws Exception {
return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}
到这里我们已经知道,创建了一个WebDataBinderFactory,它包含了很多类型转换器,接下来就是创建ModelFactory
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
Class> handlerType = handlerMethod.getBeanType();
Set methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
methods = HandlerMethodSelector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
List attrMethods = new ArrayList();
// Global methods first
for (Entry> entry : this.modelAttributeAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
}
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
过程和创建WebDataBinderFactory类型,ModelFactory的作用是在控制器方法调用前初始化Model模型,调用后对Model模型进行更新操作。既然binderFactory和modelFactory都已经被创建出来了,接下来就是对handlerMethod进行再次封装了,接着invokeHandlerMethod方法往下走
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
//ServletInvocableHandlerMethod的作用就是对处理器方法的返回
//值进行相关的处理,同时还有ResponseStatus
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//实例化容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//把request中的DispatcherServlet.INPUT_FLASH_MAP,重定向
//参数注入到容器的model模型中,FlashMap的作用是在redirect中传递参数。
//重定向是会生成新的request,传递参数就不能直接用request进行传递
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
...
return getModelAndView(mavContainer, modelFactory, webRequest);
}
实例化ModelAndViewContainer容器,它主要是用来返回Model对象的,在容器中有两种Model一个是defaultModel,另一个是redirectModel,redirectModel用于传递redirect时的参数。
接下来看看modelFactory.initModel(webRequest, mavContainer, invocableMethod);做了什么事情
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
throws Exception {
Map sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
mavContainer.mergeAttributes(sessionAttributes);
invokeModelAttributeMethods(request, mavContainer);
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!mavContainer.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
}
mavContainer.addAttribute(name, value);
}
}
}
从request中获取@SessionAttribute的属性,先存在map结构中,然后执行了invokeModelAttributeMethods(request, mavContainer);方法
/**
* Invoke model attribute methods to populate the model.
* Attributes are added only if not already present in the model.
*/
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
throws Exception {
while (!this.modelMethods.isEmpty()) {
InvocableHandlerMethod attrMethod = getNextModelMethod(mavContainer).getHandlerMethod();
//把@ModelAttribute注解的handlerMethod中的模型添加到容器中的model中
String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
if (mavContainer.containsAttribute(modelName)) {
continue;//只有当容器中不存在@ModelAtrribute中的属性时才加入
}
//取出所有的参数并且利用容器中包含的参数解析器进行解析,完成后
//取得HandlerMethod属性方法和对应的bean对象,利用反射机制执行此方法
//获取返回值
Object returnValue = attrMethod.invokeForRequest(request, mavContainer);
//如果HandlerMethod方法不是void的
if (!attrMethod.isVoid()){
//如果@ModelAtrribute注解设置了value值,则此值
//作为返回值的名称,如果没有设置,则选择被@ModelAtrribute注解
//注解的handlerMethod的返回类型名称(首字母小写)作为model中的key
//如果这个返回类型是数组或集合,那么这个名称是返回类型名称再拼接上"List"
//如果返回类型是String或者是map,那么key就是map或string
String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
if (!mavContainer.containsAttribute(returnValueName)) {
mavContainer.addAttribute(returnValueName, returnValue);
}
}
}
}
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//解析获取参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
//执行
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//取到所有的参数
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//使用对应的解析器去解析参数
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
throw new IllegalStateException(msg);
}
}
return args;
}
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
//反射机制执行方法
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
throw new IllegalStateException(getInvocationErrorMessage(ex.getMessage(), 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);
}
}
}
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
public static String getNameForReturnValue(Object returnValue, MethodParameter returnType) {
ModelAttribute annotation = returnType.getMethodAnnotation(ModelAttribute.class);
if (annotation != null && StringUtils.hasText(annotation.value())) {
return annotation.value();
}
else {
Method method = returnType.getMethod();
Class> resolvedType = GenericTypeResolver.resolveReturnType(method, returnType.getContainingClass());
//这个方法是判断如果返回的是object类型,那么就会通过实现的返回类型推测出
//类的简称
return Conventions.getVariableNameForReturnType(method, resolvedType, returnValue);
}
}
再回到initModel()方法上,分析接下来的代码
//遍历handlerMethod的参数,判断是否有被@ModelAttribute注解的
//如果有,则继续判断这个参数和类型是否和当前handlerMethod所在类
//中的@SessionAttribute注解中的参数和类型一致
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!mavContainer.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
}
//把名称和值添加到model中,这里的model是defaultModel
mavContainer.addAttribute(name, value);
}
}
private List findSessionAttributeArguments(HandlerMethod handlerMethod) {
List result = new ArrayList();
for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
String name = getNameForParameter(parameter);
if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, parameter.getParameterType())) {
result.add(name);
}
}
}
return result;
}
接着再回到
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
//处理一些异步请求
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);
}
//调用invokeAndHandle方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
我们来看看invokeAndHandle,从给定请求中解析handlerMethod的参数,调用此方法,并获取handlerMethod的返回值,具体的过程与上面的执行属性方法类似
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//如果有使用@ResponseStatus注解来设置响应状态时则设置responseStatus
setResponseStatus(webRequest);
//如果返回值为空,则状态是否是request请求或者返回状态有值时
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);//直接使用response来处理返回
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
//如果不使用response来处理,则设置为false,使用view来处理返回
mavContainer.setRequestHandled(false);
try {
//遍历所有的返回值处理器,通过supportsReturnType()
//来找到支持此返回值类型的处理器
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;
}
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
Assert.notNull(handler, "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;
}
我们再回到RequestMappingHandlerAdapter中的invokeHandlerMethod()方法,接下来,还剩下
return getModelAndView(mavContainer, modelFactory, webRequest);
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//查看下面updateModel中的解释
modelFactory.updateModel(webRequest, mavContainer);
//如果容器采用的是response直接处理的方式,说明不采用view
//的方案,直接返回null即可
if (mavContainer.isRequestHandled()) {
return null;
}
//采用的是view方案,获取默认的model,将此model和视图名称
//直接填充到ModelAndView中,创建一个ModelAndView出来
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
//return (this.view instanceof String);如果容器中的view不是string的话
//就设置此视图对象,如果是string说明是逻辑视图名称,等待下一步处理
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//如果model是RedirectAttributes的实例,
//那么说明是model是重定向所需要的属性,我们把model填充到FlashMap即可
if (model instanceof RedirectAttributes) {
Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
ModelMap defaultModel = mavContainer.getDefaultModel();
//获取默认的model对象,判断当前会话是否完成,如果完成
//则清理相关的资源,如果没有完成,则把当前request中
//的model对象保存在sessionAttributeStore方便下次请求
//
if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, defaultModel);
}
if (!mavContainer.isRequestHandled() && mavContainer.getModel() == defaultModel) {
updateBindingResult(request, defaultModel);
}
}
再返回到上一步RequestMappingHandlerAdapter中的hanlderInternal()方法中,方法已经执行完成,接着返回到RequestMappingHandlerAdapter中方法也执行完成,接着再返回到AbstractHandlerMethodAdapter中的handler方法,即在doDispatch方法中执行的mv = ha.handle(processedRequest, response, mappedHandler.getHandler());此时我们得到了ModelAndView对象。接下来就是如何把Model绑定到相应的view的问题了。
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;
...........
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果mv中没有视图名称,则设置默认的视图名称
applyDefaultViewName(processedRequest, mv);
//执行 在执行链中的所有拦截器的postHandle方法对返回的结果再次处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//对返回结果进行处理,详见下面 processDispatchResult方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
}
}
}
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
//判断是否有异常存在,如果有则再判断是否是ModelAndViewDefiningException
//如果是则把视图解析成ModelAndViewDefiningException需要的类型
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
//如果是其它异常,
//就让HandlerExceptionResovlers中的异常解析器来处理
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//如果mv不为空且mv中的model和view没有被清理
//则执行render
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;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
//render的作用就是判断mv中的视图是否是逻辑视图名称,如果是,
//则去视图解析器中找到对应的物理视图对象,找到后直接执行视图的render方法
//完成渲染工作
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;
if (mv.isReference()) {
// We need to resolve the view name.
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 {
//调用它本身的render方法把model对象填充到view中,完成渲染工作
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;
}
}
protected View resolveViewName(String viewName, Map 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;
}
到现在为止,dispatch方法主体才执行完成,后续还有一些清理的方法不再描述。可以看到springmvc在处理请求的时候还是先复杂的,这个主要是由于springmvc具有很强的扩展性,在请求的名阶段都可以干预请求的处理和处理结果。