在SpringMvc启动以及加载过程中以及讲到Spring启动加载过程,现在看下以及请求进来的过程以及数据流转过程,首先在看源码之前简单对SpringMvc请求过程有一个简单的大方向的了解:
第一步就是获取,然后在Web Spring获取后根据request 中url来从HandlerMap查询Handler
第二步
- 请求数据经过DispatchServerlet
- 通过request 获取url查询Handler
- Handler调用相应的 Controller方法获取结果
- 组装成ModelAndView
- ModelAndView解析成view
- 返回给客户端
可以看到DispatchServlet是控制整过的控制者,以及逻辑分发者接下在再看下该类的UML图,可以看到这个类主要是Spring以及Servlet的一个桥梁既有实现接口Servlet相关的接口,也有Spring相关的接口,一开始主要这里主要涉及Servlet接口相关的。从UML图可以看到它是HttpServlet的子类,那么他有一个很重要的一个性质接受用户的请求,web配置的URL请求拦截的请求都会通过该类的
void service(HttpServletRequest req, HttpServletResponse resp)
方法处理。从代码上看,这个类的service方法主要通过父类FrameWorkServlet实现:
FrameWorkServlet.service:
/**
* Override the parent class implementation in order to intercept PATCH requests.
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取请求方法:POST GET PUT 等
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);
}
else {
//调用HttpServlet service方法
super.service(request, response);
}
}
再看下父类HTTPServlet的方法:
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) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
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 {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
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);
}
}
这块代码功能很简单就是获取请求的 方法类型,不同的请求类型走不同的逻辑,这些可以交给子类实现,这里用了模板模式,在FrameServlet重写了些 doGet doPost方法:
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
每一个方法最后都会调用processRequest这个方法,而这个方法最核心的是调用了
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
这个方法被DispatchServlet实现了,也就是说:一个请求过来最终的公共逻辑会走到DispatchServlet#doService方法。
接下来就是真正的逻辑开始了。这个方法看代码其实最核心的调用
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception
所以我们直接从这个方法开始看:
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 {
//将请求转化解析,如果是文件上传的请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//获取处理Handler(重点)
mappedHandler = getHandler(processedRequest);
//没有找到Handler 说明404啦
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//获取一个适配器(重点)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//这里执行所有的和这个请求有关的拦截器,执行preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//适配器调用Handler方法,处理请求以及Handler,获取modelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//这里执行所有的和这个请求有关的拦截器,执行postHandle方法
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);
}
}
}
}
这里我们重点关注一下几个过程:
- 获取MapHandler过程,以及这个对象包含的信息
- HandlerAdapter执行过程
- HandlerAdapter角色作用
接下来我看从这三个方面来看下,下面都是基于注解的方式来走的(@Controller @RequestMapping)
MapHandler的获取
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//从HandlerMapping中获取Handler
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
在this.handlerMappings代表配置不同的类型,我们直接看debug的截图:
可以看到有三个HandlerMapping,其中SimpleUrlHandlerMapping是配置加载的,BeanNameURLHandlerMapping是默认实现的,RequestMappingHandlerMapping是基于@Controller @RequestMapping实现的。所以我们只用了注解实现的,我们只关心这块逻辑就好。接下来看下Mapping的getHandler方法:
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取一个Handler对象
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 = getApplicationContext().getBean(handlerName);
}
//获取这个请求相关的拦截器,并且和Handler组装成一个对象
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;
}
以上代码只完成两个事情:获取一个请求相关的Handler 以及拦截器,看下这两个方法:
获取Handler
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取请求URL
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
//加一个共享锁
this.mappingRegistry.acquireReadLock();
try {
//获取HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
//生成创建Handler
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//获取一个Match对象,在下面看下这个debug数据内容(标注1)
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//把可以和这个匹配的Match对象加入一个List中(标注2)
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()) {
//把刚刚的Matches排序(标注3)
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
//获取最优的Match
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
//有两个一样Match,那么就会抛出异常
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
//返回Match的handlerMethod
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
//将拿到的match和mapping包装成一个对象
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
上面两个方法主要获取Handler的过程:
- 首先获取T泛型集合(这个T是一个啥)
- 将Match集合排序获取最优的(是啥排序策略)
- 返回最优Match.Handler(这个又是一个啥)
上面我们知道了这个过程,但是对里面的数据却没有一个感性的认识,现在直接看debug数据就行。
首先看下标注1,获取一个List,其实是从this.urlLookup这个Map中获取的:
这个数据结构内容是,key放的是我们的Url,value是一个list,list的每一个对象是怎么来的呢?其实这个数据来源就是注解@RequestMapping中各个转化的内容,也就是一个出现多个一样的的Url的处理方法(后面会有如何选其中的一个方法)。回答第一个问题,T是一个包含了注解信息的对象,包括 url Post/Get 等
然后就到了注解2,把我们刚刚拿到的所有的注解的信息会构造一个Match,拿着之前注解信息还会从this.mappingRegistry获取一个Handler。
我们可以看到获取的value是一个HandlerMethod对象,它是记录的主要是方法的信息,例如这个url对应的Controller bean Method,以及方法的参数信息(第三个对象答案)。也就是一个Match对象有一个@RequestMapping注解信息以及方法的信息
接下来看下标注3,标注3主要对多个Match进行选取最优的Match,有两个最优的那么就会抛异常,我们从代码获取比较器一步步走进去我们可以看到最终是按照@RequestMapping信息对象(RequestMappingInfo)来排序的(上面第二个问题的答案),,这里就不详细看了,里面代码比较简单。
以上就是获取Handler的逻辑:
- 根据URL获取注解的信息对象
- 根据注解信息对象获取具体的方法信息对象
- 根据注解信息对象排序选出最优的哪一个方法信息Handler 返回,反之就会抛异常
HandlerInterceptor获取
在获取完Handler后获取拦截器,组装成 HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
//拦截器可以匹配URL,就会加入到链表中
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
HandlerAdapter
我们在上面一部已经获取了URL对应的Handler,里面主要的要的处理的方法信息,这个请求交给哪一个Controller的哪一个方法,现在HandlerAdapter其实起的是一个执行的过程,以及提供各种上下文的对象完成数据映射转换,并且调用方法完成业务逻辑。
/**
* 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 + "]");
}
//获取可以支持的适配器,这个和controller配置有关系,注解实现的返回RequestMappingHandlerAdapter
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");
}
这里按照注解实现那么就会返回RequestMappingHandlerAdapter,从主流程handle->handleInternal->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);//构建执行器
//设置请求参数到Controller转换对象
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();
}
}
上面的流程就是通过Handler以及上下文一些工具对象(各种Convert类)构建一个新的执行类进行执行。
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) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//对返回的参数进行转换写入到Response中
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;
}
}
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//转化获取controller需要的值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
//通过反射调用bean的处理方法,拿到返回值
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
上面的逻辑主要分为两步:
- 获取controller方法执行的参数
- 通过反射执行方法
接下来看下参数的获取过程:
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取controller参数信息
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] = 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("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
这一步主要识别一些根据参数以及标记例如注解等来拿到 HandlerMethodArgumentResolver 对象,例如参数带了 @RequestJsonbody 会有一个专门的类RequestResponseBodyMethodProcessor 来获取参数,带了@RequestParam 会有RequestParamMethodArgumentResolver类来获取参数。
还要一部就是在拿到返回值对返回值也有一个类似的转化的流程在
invokeAndHandle->this.returnValueHandlers.handleReturnValue
中,会调用
@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;
}
这里如果通过拿到返回值得信息,例如注解,类等信息,决定拿到哪一个
HandlerMethodReturnValueHandler
来处理返回值。
以上就是主要的流程,回顾一下:
- 获取Servlet请求
- 获取请求 Url获取具体符合的方法集合
- 选取最优的方法
- 获取转换的Controller方法的执行参数
- 反射执行
- 获取结果,并且转换设置到Response中