目录
一、传统Serlvet源码运行流程
调用传统的servlet流程如下:
- 如果是第一次调用servlet则调用其init方法,初始化serlvet,该方法只会在第一次加载serlvet时被调用;
- web服务器将请求封装成Request,同时生成一个Response对象,后续传入service方法;
- 调用完service方法后再调用destroy方法。
二、SpringMVC源码运行流程
具体流程图如下:
SpringMVC本质上是基于Servlet运行的,对其进行框架的一系列封装,其大致流程如下:
- 运行前在web.xml中配置DispatcherServlet,其和普通的Servlet配置一样;
- 像传统的Servlet流程一样,先调用DispatcherServlet的init方法,SpringMVC在init方法中加入了本框架必须的一些初始化流程,上一篇着重讲的便是init流程,若有兴趣可看文章(三)SpringMVC原理解析之启动源码分析;
- 后续调用service方法,SpringMVC能够实现如此便利的配置以及使用方式便是对该方法进行了另外的封装,在此流程中加入框架的流程,使得其与传统的Servlet无缝连接;
- FrameworkServlet类继承了HttpServletBean类,重写了service方法,在该方法中调用了processRequest方法,无论是get、post还是put、delete等请求方式,最终都会跳转到该方法中来,途中不会做任何处理,并且进入此方法开始,SpringMVC就会记录开始时间;
- 在processRequest方法中,调用doService方法,该方法在DispatcherServlet中,在该方法中设置完一系列request属性后接着调用doDispatch方法,在该方法中是进行处理url对应handler以及其对应的adapter的主要地方;
- 而调用进具体的Controller则是在HandlerAdapter的具体实现类中完成,调用完该实现类的hanlde方法后便进入了Controller的具体方法;
- 而执行完后SpringMVC对进行一系列的善后工作,如multipartRequest文件类型的会把缓存的文件给一一删除、解析相应的ModelAndView到具体的View上、执行HandlerExecutionChain中一系列拦截器、执行resetContextHolders方法以及打印整个SpringMVC调用流程的时间等日志。
大致交互流程图如下:
三、源码解析
既然SpringMVC本质上是一个Servlet,那我们就从Servlet的流程来切入SpringMVC源码运行流程。
1.Serlvet接口
Serlvet接口部分源码:
public interface Servlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
}
2.HttpServlet类
HttpServlet类部分源码:
public abstract class HttpServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
// 判断进入不同类型的方法处理
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg = lStrings
.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_put_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
response.setContentLength();
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
}
HttpServlet的子类FrameworkSerlvet重写了service接口,在其重写的接口内,只有当请求类型是PATCH或者没有明确指定请求类型时会直接调用FrameworkServlet中的方法,其它的类型都会先调用进HttpServlet的service方法,就如其源码所示,HttpServlet对doGet、doPost等方法都没有实现,而是直接返回错误码,因此可以推定,其doGet、doPost等方法都是调用进了实现子类中。接下来看到FrameworkServlet子类源码。
3.FrameworkServlet类
其部分源码如下:
public abstract class FrameworkServlet extends HttpServletBean
implements ApplicationContextAware {
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
@Override
protected final void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext =
LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder
.getRequestAttributes();
ServletRequestAttributes requestAttributes =
buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class
.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
doService(request, response);
} catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext,
previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
publishRequestHandledEvent(request, response, startTime,
failureCause);
}
}
private void publishRequestHandledEvent(HttpServletRequest request,
HttpServletResponse response, long startTime, Throwable
failureCause) {
if (this.publishEvents) {
// 不管是否执行成功,最终都会调用该方法
long processingTime = System.currentTimeMillis() - startTime;
int statusCode = (responseGetStatusAvailable ?
response.getStatus() : -1);
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig()
.getServletName(),
WebUtils.getSessionId(request),
getUsernameForRequest(request),
processingTime, failureCause, statusCode));
}
}
}
看其源码可知道任何请求形式都会进入到processRequest方法中,并且在该方法中会对localeContext以及RequestAttributes进行一定的处理,处理之后便会直接调用doService方法,该方法在其子类DispatcherSerlvet中实现。当调用完doService之后在SpringMVC中实际上已经算请求完成了,只是后续会调用publishRequestHandledEvent方法将执行的时间以及request名字、session等用日志打印出来。
4.DispatcherServlet类
运行时,DispatcherServlet类的切入点为doService方法,其部分源码如下:
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void doService(HttpServletRequest request,
HttpServletResponse response) throws Exception {
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));
}
}
}
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()) {
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
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 {
// 判断是否是文件类型,如果是则返回文件类型request
// 如果不是则直接返回原对象
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取处理类
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null ||
mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据处理类获取Adapter适配器
HandlerAdapter ha =
getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request,
mappedHandler.getHandler());
if (new ServletWebRequest(request, response)
.checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际调用处理程序
mv = ha.handle(processedRequest, response,
mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 处理mv对象返回值
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler" +
" dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler,
mv, dispatchException);
} catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
ex);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler
.applyAfterConcurrentHandlingStarted(
processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
// 如果上传的是文件类型,调用完则清除文件缓存
cleanupMultipart(processedRequest);
}
}
}
}
}
DispatcherServlet的doService方法流程如下:
- 如果请求类型是include类型,则创建一个request属性快照,保存起来;
- 将ApplicationContext、localeResolver以及themeResolver等对象存放进Request属性中;
- 调用doDispatch方法。
DispatcherServlet的doDispatch方法流程如下:
- 调用checkMultipart方法判断是否是文件上传,如果是则返回multipartResolver对象解析之后的request对象,如果不是文件上传则返回原来request,将判断结果赋给multipartRequestParsed;
- 调用getHandler方法,获得具体的HandlerExecutionChain mappedHandler对象,如果返回的对象为空则调用noHandlerFound方法,然后直接返回结束请求;
- 调用getHandlerAdapter方法,返回HandlerAdapter ha对象;
- mappedHandler调用applyPreHandle方法,如果返回false则直接返回;
- ha对象直接调用handle方法,完成实际的SpringMVC方法调用处理;
- 如果调用的方法是异步的,则调用asyncManager.isConcurrentHandlingStarted方法返回为true,直接返回,不执行后续步骤;
- 调用applyDefaultViewName,获取view的名称;
- 调用mappedHandler.applyPostHandle方法,调用后续的拦截器处理请求;
- 调用processDispatchResult方法;
- 如果multipartRequestParsed标识(即是否是上传文件)为true,调用cleanupMultipart方法,将文件缓存清除。
4.1 checkMultipart方法
该方法源码如下:
protected HttpServletRequest checkMultipart(HttpServletRequest request)
throws MultipartException {
if (this.multipartResolver != null &&
this.multipartResolver.isMultipart(request)) {
if (WebUtils.getNativeRequest(request,
MultipartHttpServletRequest.class) != null) {
// 不执行操作
} else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE)
instanceof MultipartException) {
// 不执行操作
} else {
// 如果解析判断是带有文件的对象,则返回文件封装request
return this.multipartResolver.resolveMultipart(request);
}
}
// 如果之前未返回则直接返回原来的request对象
return request;
}
可以看到,该方法主要使用的是multipartResolver成员对象,如果调用该对象的isMultipart方法返回为true且之前未抛出异常等,则调用该对象的resolveMultipart方法,将普通的request转换为MultipartHttpServletRequest对象。
multipartResolver对象一般而言有两种类型,StandardServletMultipartResolver和CommonsMultipartResolver两种,CommonsMultipartResolver类型需要依赖第三方的包才能实现。
在resolveMultipart方法中基本上就是将request中的文件一一取出来,并赋予文件属性名称封装进MultipartHttpServletRequest实现对象。
4.2 getHandler方法
该方法源码如下:
protected HandlerExecutionChain getHandler(HttpServletRequest request)
throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
// 多个handler,判断哪个handler能够处理这个request请求
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
public abstract class AbstractHandlerMapping
extends WebApplicationObjectSupport
implements HandlerMapping, Ordered {
@Override
public final HandlerExecutionChain getHandler(
HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain =
getHandlerExecutionChain(handler, request);
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;
}
}
可以看到,该方法只做了一件事便是遍历成员对象handlerMappings,并调用其getHandler方法,如果返回不会空则返回该HandlerExecutionChain对象。
在该demo里面,handlerMappings对象一共有三个:RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping,其中RequestMapping是从Spring的xml文件中<mvc:annotation-driven/>标签的处理类AnnotationDrivenBeanDefinitionParser中初始化的,当然BeanNameUrl从这里面也会初始化,而SimpleUrl是从标签<mvc:default-servlet-handler/>中的DefaultServletHandlerBeanDefinitionParser处理类获得的,BeanNameUrl也可以从这里获得。
一般普通的url请求都会被RequestMappingHandlerMapping对象处理,返回的handler对象如果是controller中的方法,一般都是对应的Controller类。
其次可以看到AbstractHandlerMapping类中的getHandler方法,如果请求方式不支持在方法getHandlerInternal中便会检测出并抛出HttpRequestMethodNotSupportedException异常。
4.3 getHandlerAdapter方法
该方法源码如下:
protected HandlerAdapter getHandlerAdapter(Object handler)
throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
// 判断adapter适配器和handler的对应支持关系
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("...");
}
可以看到该方法和getHandler方法可以说是一个模子刻出来的,在该demo中,handlerAdapters也拥有三个值:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter以及最后的RequestMappingHandlerAdapter。其中HttpRequest和SimpleController可以在标签<mvc:default-servlet-handler/>的处理类DefaultServletHandlerBeanDefinitionParser以及标签<mvc:annotation-driven/>的处理类AnnotationDrivenBeanDefinitionParser中注册进Spring,RequestMapping则是在AnnotationDrivenBeanDefinitionParser和RequestMappingHandlerMapping一起被注入进Spring中的。
平时使用Controller时,handler则是封装了controller的对象,RequestMappingHandlerAdapter对象的supports方法判断的是如果HandlerMethod类型则返回该适配器。
会有上述流程效果是因为RequestMappingHandlerAdapter和RequestMappingHandlerMapping这两个对象都是在标签<mvc:annotation-driven/>的处理类AnnotationDrivenBeanDefinitionParser完成注册的,因此可以堪称这两个类是配套存在的,在HandlerMapping中会将@RequestMapping和@Controller注解的类全都读取,并且将controller中被@RequestMapping注解的方法全都用HandlerMethod封装起来,存放到context上下文中,而HandlerAdapter则只需要判断handler是不是HandlerMethod类型就可以完成配套判断。
4.4 handle方法
按照当前逻辑来HandlerAdapter接口实现类RequestMappingHandlerAdapter的handle方法源码如下:
public abstract class AbstractHandlerMethodAdapter
extends WebContentGenerator implements HandlerAdapter, Ordered {
@Override
public final ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
}
public class RequestMappingHandlerAdapter
extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod)
throws Exception {
ModelAndView mav;
checkRequest(request);
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 调用处理方法,获得ModelAndView对象
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod)
.hasSessionAttributes()) {
applyCacheSeconds(response,
this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
protected final void checkRequest(HttpServletRequest request)
throws ServletException {
// 检查是否支持request请求方法
String method = request.getMethod();
if (this.supportedMethods != null &&
!this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(
method, StringUtils.toStringArray(this.supportedMethods));
}
if (this.requireSession && request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session" +
" required but none found");
}
}
}
该方法首先会调用checkRequest方法,在该方法中进行该类所支持的request检查,在该类中进行的是请求方式及requestSession是否存在的判断。当判断通过后无论是异步还是同步,都会最终进入invokeHandlerMethod方法,在该方法中具体调用被@RequestMapping注解注释的方法。至于invokeHandlerMethod方法的具体调用流程我们稍后再进行分析,先分析调用完之后的流程。在调用完invokeHandlerMethod方法后会判断请求头是否有Cache-Control的属性,对该属性进行处理。
4.5 invokeHandlerMethod方法
RequestMappingHandlerAdapter类中的方法invokeHandlerMethod源码如下:
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;
}
// 获得具体的ModelAndView对象
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
该方法的具体流程如下:
- 先将request和response使用ServletWebRequest封装成对象webRequest;
- 调用getDataBinderFactory方法,处理@InitBinder注解;
- 调用getModelFactory方法处理@ModelAttribute注解;
- 使用ServletInvocableHandlerMethod对象invocableMethod封装HandlerMethod方法;
- 接着将参数解析器以及返回值处理器、处理@InitBinder的对象赋值给invocableMethod;
- 创建ModelAndViewContainer对象mavContainer,用来保存model和view;
- 创建WebAsyncManager异步处理对象asyncManager,判断是否需要进入异步调用;
- 调用invocableMethod对象的invokeAndHandle方法,完成实际的调用;
- 使用asyncManager.isConcurrentHandlingStarted()判断如果是异步,则直接返回null,处理流程交给异步流程处理;
- 调用getModelAndView方法,获得具体的ModelAndView;
- 调用webRequest.requestCompleted()方法完成请求的最终处理。
在该流程中,值得仔细研究的便是invokeAndHandle方法,接下来我们仔细分析。
4.6 invokeAndHandle方法
ServletInvocableHandlerMethod类中的方法invokeAndHandle源码如下:
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs)
throws Exception {
// 调用实际处理方法并获得返回值
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 {
// 处理返回值
this.returnValueHandlers.handleReturnValue(returnValue,
getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}
在该方法中,invokeForRequest方法和后面的handleReturnValue方法是最重要的,一个是处理request请求,一个是处理返回值,中间只是对returnValue和response进行一定的处理。
如setResponseStatus是对request请求后解析返回值状态是否正常,如果不正常则将错误信息返回。
4.7 invokeForRequest方法
ServletInvocableHandlerMethod类中的invokeForRequest方法以及调用方法源码如下:
public Object invokeForRequest(NativeWebRequest request,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获得请求的参数
Object[] args = getMethodArgumentValues(request, mavContainer,
providedArgs);
// 传入参数进行实际方法调用
Object returnValue = doInvoke(args);
return returnValue;
}
方法中先调用了getMethodArgumentValues方法,获取从前端传过来的参数,并正确返回,随后调用doInvoke将获得的方法参数使用反射调用到具体的方法。
4.8 getMethodArgumentValues方法
getMethodArgumentValues方法源码如下:
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) {
throw ex;
}
}
if (args[i] == null) {
String msg = getArgumentResolutionErrorMessage("No suitable" +
" resolver for argument", i);
throw new IllegalStateException(msg);
}
}
return args;
}
其方法流程如下:
- 在使用HandlerMethod对象封装被@RequestMapping注解注释的方法时,会将被封装的方法的参数类型等全都封装在对象中,因此要获得参数直接使用成员变量parameters即可;
- 使用parameterNameDiscoverer对象对参数名字进行处理;
- 调用GenericTypeResolver.resolveParameterType方法解析参数类型;
- 调用resolveProvidedArgument方法从提供的参数providedArgs获得参数类型;
- 调用argumentResolvers.supportsParameter方法来判断参数是否支持某种类型的参数解析器,如@RequestParam是被RequestParamMethodArgumentResolver对象解析的,而@RequestBody是被RequestResponseBodyMethodProcessor对象解析处理的;
- 调用argumentResolvers.resolveArgument()方法使用相应的参数解析器来处理解析参数并返回。
需要注意的是supportsParameter()方法和resolveArgument()里面还有一些逻辑,但大体而言一看便知道了,因此不仔细深入,点到为止。如果需要看具体的注解是如何解析成方法参数的可以仔细去看对应注解的参数解析器。
4.9 doInvoke方法
doInvoke方法源码如下:
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 通过反射调用实际的方法
return getBridgedMethod().invoke(getBean(), args);
} catch (InvocationTargetException ex) {
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);
}
}
}
可以明确的看到当拿到方法参数传入进来后,该方法就使用反射调用了对应的方法和传入相应的参数,以实现具体进入到被@RequestMapping注解注释的方法中并返回其方法返回值。
4.10 handleReturnValue方法
HandlerMethodReturnValueHandlerComposite类中的方法源码如下:
@Override
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;
}
可以看到该方法和参数解析器的流程差不多,都是使用一个方法去遍历对应的处理器,看加载的处理器哪个处理器支持该类型的处理,如果符合则返回并调用方法handleReturnValue()并返回其返回值,如我们经常使用的@ResponseBody使用的便是RequestResponseBodyMethodProcessor类,该类的supportsReturnType方法便是判断@ResponseBody注解的,而handleReturnValue方法则是对返回值进行json转换输出真正处理的地方。
讲到这里基本上SpringMVC的启动原理以及一般流程的运行原理已经完成了,SpringMVC暂时告一段落,一些其它的原理以及配置原理有时间再开另一篇详细分析。