SpringMVC源码引入
SpringMVC本质上是对Servlet的封装,所以SpringMVC内部一定有一个类实现了原生的javax.servlet.http.HttpServlet,发现org.springframework.web.servlet.FrameworkServlet继承了原生的HttpServlet实现了doGet doPost doXXX的方法
以doGet为例
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
发现底层调用了processRequest方法
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
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
其中最核心的doService方法实现MVC核心逻辑,进入doService方法是调用了org.springframework.web.servlet.DispatcherServlet类的方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(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<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
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());
if (this.flashMapManager != null) {
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);
}
// 前面的都是对request请求添加属性 和 一些上下文初始化操作
try {
// 逻辑的核心是doDispatch方法 该方法实现了对请求路径转发到对应处理器逻辑
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);
}
}
}
}
查看源码发现最核心的是doDispatch方法,该方法中封装了请求路径转发到对应的处理器,封装ModelView参数,body参数封装等逻辑
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 重新包装一下request
HttpServletRequest processedRequest = request;
// 处理器执行链 是 url-> controller方法的核心 包含了目标方法处理和拦截器
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// 是否异步
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
// ModelAndView 逻辑
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 查看是不是文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 核心获取handler的方法
mappedHandler = getHandler(processedRequest);
if (mappedHandler == 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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 拦截器的前置处理的逻辑 如果返回false 直接不会调用目标方法
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);
}
}
}
}
SpringMVC如何将找到具体URL应该由哪个处理器来执行
先看看getHandler获取 处理器的方法细节
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// 遍历系统里面所有的handlerMapping 找到一个合适的handler来处理
// 并包装成一个HandlerExectuionChain返回
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
Spring已经帮我们准备了5个默认的handlerMapping
RequestMappingHandler处理所有@RequestMapping标记的处理器
RouterFunction处理WebFlux的RouterFunction的路径处理器
进入getHandler详细
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 核心逻辑
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 将handler 包装成一个handlerExectuionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ..非核心逻辑省略
return executionChain;
}
进入getHandlerInternal内部逻辑
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// 调用AbstractHandlerMethodMapping的lookupHandlerMethod找到HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 核心处理映射方法的逻辑
/** 内部细节
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
// 处理各种跟请求路径相关的操作 返回一个RequestMappingInfo对象包装了这个请求的路径请求方式等信息
T match = getMatchingMapping(mapping, request);
if (match != null) {
// 从mappingRegsitry中找到能处理这个urlMapping的具体的controller中的方法,此处返回之后就会在matches 添加一个Match装配上了各种url信息和controller信息
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
*/
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()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
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);
// 处理匹配逻辑 里面处理了 pathVariable matrixVariable底层会用了Spring的工具类org.springframework.web.util.UrlPathHelper
/**
Set<String> patterns = info.getPatternsCondition().getPatterns();
if (patterns.isEmpty()) {
bestPattern = lookupPath;
uriVariables = Collections.emptyMap();
}
else {
bestPattern = patterns.iterator().next();
// 处理pathVariable
uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
}
*/
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
此时方法返回HandlerMethod回到了AbstractHandlerMapping的getHandler方法继续往下执行
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 处理完了获得了MethodHandler继续往下执行
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 将MethodHandler包装成HandlerExectuionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
包装HandlerExectuionChain里面包装了拦截器的逻辑
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
// 获取拦截器 添加到chain中
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;
}
此时的处理器已经包装成了chain 并添加了拦截器,此时才真正的从url请求路径转换成了Spring中Controller的方法回到了DispatcherServlet的doDispatch方法继续往下执行
获取HandlerAdapter
HandlerAdapter是Spring Web中的一个接口用于真正执行目标方法,返回ModelAndView对象,该接口有2个核心方法support判断是否处理.handler真正使用反射调用目标方法并包装成ModelAndView对象返回
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
public interface HandlerAdapter {
// 是否支持
boolean supports(Object handler);
// 真正处理调用
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 获取最后一次修改时间
long getLastModified(HttpServletRequest request, Object handler);
}
DispatcherServlet中的getHandlerAdapter方法的细节
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
// 获取Spring为我们准备的所有HandlerAdapter 处理遍历,调用Support方法如果支持返回这个Adapter
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
以我们常用了RequestMappingHnadlerAdapter为例看看support到底做了什么
public final boolean supports(Object handler) {
// 判断是不是一个 HandlerMethod true 然后继续调用supportInternal方法继续判断
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
// RequestMappingHandlerAdapter 里面判断简单粗暴只是返回true 意思是如果我们处理器是HandlerMethod的实例就可以使用RequestMappingHandlerAdapter处理
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
此时返回到DispatcherServlet继续往下执行
// 获取到了具体的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//.. 中间省略各种判断逻辑直接来到最核心的handlerAdapter的 handler方法最终通过反射调用目标方法的核心逻辑
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// AbstractHandlerMethodAdapter 中的handler方法真正调用handleInternal的方法,而这个方法是一个抽象的具体的实现在子类实现,我们上面获取的handler是RequestMappingHandlerAdapter这里去真正调用的是该类的handler方法
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
下面继续分析RequestMappingHandlerAdapter的handleInternal方法
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// 对request进行检查 如是不是支持的方法 session是不是必须的
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
// 是不是同步 这里不是进入else逻辑
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;
}
里面最核心的就是invokeHandlerMethod方法该方法就在RequestMappingHandlerAdapter中继续追踪
@Nullable
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);
// Model的工厂
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
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的对象
// 将ModelAndView再包装成一个Container并进行一些初始化操作
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);
}
// 调用目标方法 传入封装了request response的webRequest和 ModelAndView的Container 下面研究这个方法 该方法一放过就调用了controller中的方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
参数解析器 定义了许多常用的参数解析器
如RequestParamMethodArugmentResolver 用于处理@RequestParam注解标注的属性
PathVariableMethodArgumentResolver 处理@PathVariable注解
ModelMethod… 处理Model
RquestResponseBody… 处理@RequestBody
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b1TpDrtm-1612174029770)(C:\Users\denglw\AppData\Roaming\Typora\typora-user-images\image-20210201150845242.png)]
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 调用改行就通过反射去调用了controller中的方法把返回值赋值给了Object
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
继续追中invokeForRequest方法
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取所有绑定的参数 如@RequestParam @PathVariable Model @RequestHeader等等..
// 此处包含了所有将请求中的数据包装成参数的逻辑 需要仔细分析
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
SpringMVC的参数绑定逻辑
接着上面的源码继续追到InvocableHandlerMethod的getMethodArgumentValues方法
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 找到目标方法一共有多少个参数
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
// 创建跟参数个数大小对应的Object数据
// 下面开始真正的绑定参数
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;
}
// 遍历所有的argumentResolver去找一个能处理这种类型参数的解析器
/** 底层代码 就是遍历所有的Resolver调用support 方法如果返回true说明这个参数处理器可以处理这种类型的参数
*/
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 exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
获取参数处理器ArgumentResolver的源码解析
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
// 先尝试从缓存中拿,因为是第一次请求拿不到result==null进入下面逻辑
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
// 判断是否支持这种参数的解析
if (resolver.supportsParameter(parameter)) {
result = resolver;
// 找到了之后放到一个ConcurrentHashMap中缓存起来,下次一个同一个类型的参数就直接找到这个解析器了
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
以RequestParamMethodArgumentResolver为例看一下supportParameter的具体细节
public boolean supportsParameter(MethodParameter parameter) {
// 逻辑其实很简单 判断这个参数上面是不是加了@ReuqestParam注解
if (parameter.hasParameterAnnotation(RequestParam.class)) {
// 再判断这个参数的类型是不是map 如果不是map直接返回true
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && StringUtils.hasText(requestParam.name()));
}
else {
return true;
}
}
//...省略
}
返回resolveArgument方法获取到了resolver之后开始解析参数
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 获取解析器
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
// 解析参数
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
进入resolveArgument方法查看具体的参数绑定逻辑
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 包装参数名和值的info对象
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
// 解析特殊表达式的参数名 如@Value("${spring.application.name}")
Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
// 解析参数值 此时去真实调用RequestParamMethodArugmentResolver的resolveName方法解析参数
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveEmbeddedValuesAndExpressions(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 = resolveEmbeddedValuesAndExpressions(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;
}
查看resolveName如何将参数值拿出来
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
//获取原生的request
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null) {
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
return mpArg;
}
}
Object arg = null;
// 查看是不是文件上传
MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
// 底层调用了Servlet原生的HttpServletRequest的获取参数方法
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
// 如果有值只拿第0个
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
// 此时才真正的完成了@RequestParam的参数解析
return arg;
}
此时调回AbstractNamedValueMethodArugmentResovler的resolveArugment方法继续一些其他非核心操作然后将实际的参数值返回,最终会返回到InvocableHandlerMethod的 this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory)方法继续往下执行.此时再回退到InvocableHandlerMethod的参数解析的循环继续绑定下一个参数.
其他的@PathVariable @RequestHeader流程类似,都是走for循环继续
SpringMVC调用controller目标方法执行
经过上面的步骤已经将controller方法的参数封装完毕了继续invocableHandlerMethod的invokeForRequest继续调用doInvoke方法通过反射执行controller中的目标方法
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 此时args已经从request域封装了所有参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 调用反射执行目标方法
return doInvoke(args);
}
doInvoke方法
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 调用反射执行方法
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, 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 {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
调用反射执行完目标方法后返回ServletInvocableHandlerMethod的invokeAndHandler方法继续处理
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 此时已经拿到了调用controller目标方法之后的具体返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
// 判断返回值为空的操作
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
// 如果有异常信息就会在StatusReason中体现
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 这里开始 进入returnValueHandlers 获取所有的返回值处理器 选择合适的处理器处理之后放到ModelAndViewContainer中
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
进入handleReturnValue逻辑继续查看如何选择返回值处理器
@Override
public void handleReturnValue(@Nullable 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(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
// 跟ArgumentResovler类似的逻辑也是循环遍历所有的返回值处理器调用supportReturnType方法如果是支持的就返回handler
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
SpringMVC默认的15个ReturnValueHandler
以常用的@ResponseBody注解为例,他用到了RequestResponseBodyMethodProcessor来处理他的support的方法也很简单
public boolean supportsReturnType(MethodParameter returnType) {
// 判断一下是不是被@ResponseBody标记
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
然后再调用RequestResponseBodyMethodProcessor的handlerReturnValue方法来处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
// 标记请求已经处理了
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.\
// 拿到request 和 response 对数据进行写入包装,内部用了HttpMessageConverter对消息进行转换操作
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
继续返回到RequestMappingHandler中获取到封装包的mavContainer再调用getModelAndView再将数据转成MAV返回
// 上面逻辑省略
// 调用目标方法将执行结果包装到mavContainer
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 获取modelAndView 然后标记请求处理完毕
return getModelAndView(mavContainer, modelFactory, webRequest);
此时终于又回到DispatcherServlet的中,此时已经调用完目标方法了然后继续拦截器的后置方法最最后的收尾处理,拦截器的操作包装在了HandlerExecutionChain
// 前置处理器 如果前置处理器已经失败了直接不会调用目标方法
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);
大概流程梳理
-
DispatcherServlet# doDispatch方法
-
找到能处理该请求的HandlerExecutionChain 里面包含了拦截器
-
通过HandlerExecutionChain找到具体的HandlerAdapter
-
先调用HandlerExectionChain的拦截器的前置拦截方法如果返回true才会继续往下执行如果false直接返回
-
调用HandlerAdapter的handler方法执行目标方法的具体逻辑
底层使用invokeForRequest方法真正的执行获取参数调用目标方法
- Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); 将请求中的参数绑定的目标方法的参数列表上,内部循环遍历ArgumentResolver对不同类型的参数进行不同处理的绑定规则
- doInvoke(args); 通过反射调用目标方法获取方法的返回值
-
拿到目标方法的返回值进入returnValueHandlers中找到合适的ReturnValueHandler对返回值进行处理
-
将ModelAndViewContainer转成ModelAndView对象
-
调用HandlerExectionChain中拦截器的后置通知postHandler