springMVC实现了模型与视图的分离,其中M是模型model,V是视图View,C是控制器Controller,核心类DispatcherServlet的继承关系如下:
其本质就是一个Servlet,所以处理请求关注的是 doService 方法,在doService 方法中,可以看到调用了:
doDispatch(request, response);
看看 doDispatch 做了什么:
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 {
// 检查是否是文件上传请求,通过content-type是否以"multipart/"开头判断
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 获取处理执行器链,包括了当前请求的方法和拦截器链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 获取处理器适配器,我们使用的一般是RequestMappingHandlerAdapter
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 执行目标方法,也就是真正的处理当前请求,返回ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 执行拦截器的postHandle方法
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) {
// 触发拦截器的afterCompletion方法
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);
}
}
}
}
梳理一下流程:
(1)请求来到DispatcherServlet
(2)根据请求url,找到找到处理器执行链,包含了处理请求的方法和相应的拦截器链
(3)获取处理器适配器,用来执行目标方法
(4)执行拦截器链的preHandle方法
(5)执行处理请求的方法,并返回ModelAndView对象
(6)执行拦截器链的postHandle方法
(7)根据(5)返回的ModelAndView对象,渲染视图
(8)执行拦截器链的aterCompletion方法
下面将简单分析以下两个部分:
(1)根据请求url,找到找到处理器执行链,包含了处理请求的方法和相应的拦截器链
(2)执行处理请求的方法
一、根据请求url,找到找到处理器执行链,包含了处理请求的方法和相应的拦截器链
// 获取处理执行器链,包括了当前请求的方法和拦截器链
mappedHandler = getHandler(processedRequest);
看看getHandler都做了什么:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历所有的handlerMapping,只要有一个返回不为null,就是找到了
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
可以看到,这里遍历了所有的handlerMapping,只要有一个返回不为null,就是找到了,那么handlerMappings都有哪些呢?
可以看到,待遍历的集合handlerMappings只有两个元素,一个是RequestMappingHandlerMapping,另一个是BeanNameUrlHandlerMapping,我们使用是RequestMappingHandlerMapping,跟进去,来到AbstractHandlerMethodMapping
的 lookupHandlerMethod 方法:
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
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));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
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();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
关注这一句:
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
发现,它会从MappingRegistry中获取已经注册了处理方法,key为url,value就是处理请求的方法:
这样一来,自然可以根据请求的url来获取请求的方法了。
那么,它又是怎样获取拦截器链的呢?回到AbstractHandlerMapping的getHandler方法,有这样一行代码:
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
其中,handler是处理当前请求的方法,executionChain 是最终要返回的结果
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 如果handler是HandlerExecutionChain就直接强转,否则就new一个
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 将所有的拦截器添加到HandlerExecutionChain中
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;
}
二、执行处理请求的方法
回到 DispatcherServlet 的 doDispatch 方法:
// Actually invoke the handler.
// 执行请求方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
跟进去,来到AbstractHandlerMethodAdapter
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
handleInternal详细代码如下:
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
代码有点长,重点看这句:
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
这下来到了 RequestMappingHandlerAdapter 的 invokeHandlerMethod 方法:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 将request、response包装成ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 将请求方法handlerMethod包装成ServletInvocableHandlerMethod
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//设置参数解析器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 设置返回值解析器
if (this.returnValueHandlers != null) {
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();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
重点看这句:
// 执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
在执行目标方法的过程中,会进行参数绑定,然后通过反射执行目标方法
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 执行目标方法
return doInvoke(args);
}
那么这里就是做了两件事:
(1)解析参数,获取参数值
(2)通过反射执行目标方法
难点在于如何解析参数,毕竟我们的处理请求的方法,参数是不确定的,而执行目标方法,就是通过反射,没多大的研究价值
那么接下来,看看如何解析参数:
InvocableHandlerMethod的getMethodArgumentValues方法详情:
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
if (ObjectUtils.isEmpty(getMethodParameters())) {
return EMPTY_ARGS;
}
// 获取所有的参数
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);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 如果没有参数解析器能够解析,就抛出异常
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 通过参数解析器,解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled..
if (logger.isDebugEnabled()) {
String error = ex.getMessage();
if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, error));
}
}
throw ex;
}
}
return args;
}
这个方法的逻辑是,先获取所有的参数,然后遍历参数,逐个赋值
// 通过参数解析器,解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request,this.dataBinderFactory);
值得注意的是,不同类型的参数,会使用不同的参数解析器,参数解析器多达26个,那么如果判断参数解析器是否支持指定参数的解析呢?请看HandlerMethodArgumentResolverComposite的getArgumentResolver方法:
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
// 从缓存中获取
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
// 遍历所有的参数解析器,调用其supportsParameter来判断是否支持
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
// 将支持该参数解析的参数解析器放入缓存中
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
这里的参数解析器很多,比如RequestParamMethodArgumentResolver,就是用来解析添加了@RequestParam参数的,而PathVariableMethodArgumentResolver则是用来解析添加了@PathVariable参数的,我们常用的解析pojo对象的是ServletModelAttributeMethodProcessor这个参数解析器。
对于简单类型的参数,最后都是通过request.getParameter方法来获取参数值的
而对于pojo对象,则是先创建对象,再通过反射设置属性值的
这里的实现都比较复杂,我也只是看了一个大概,就是简单记录一下