上一节,我们只是从总体上分析了springMVC的请求处理流程,但针对每一步的细节,具体还有哪些操作并没有说明,这一节,就请求过程中的很一步处理给出相应的分析说明。
假设在服务器部署了一个工程project,其中有一个业务是根据用户ID获取用户的详细信息,GET请求的URL是:http://localhost:8080/project/userController/getUserInfo?id=10001(不考虑有其它服务器转发),当服务器接收到浏览器发送的这个请求后,按httpServlet的规范,首先会找到DispatcherServlet中的doGet方法,发现此方法在DispatcherServlet的父类FrameworkServlet中
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
发现它直接委托给了processRequest去执行(其它的方法,如:doPost,doPut等也都是委托给这个方法去处理),我们来看看processRequest方法内容
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//先取上一次的本地上下文,其实就是取Locale的信息,比如:国家,语言等等
//主要是缓存,以便后面的恢复
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//新建一个LocaleContext
LocaleContext localeContext = buildLocaleContext(request);
//取上一个请求的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//新建一个RequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//异步管理类,这个是内部使用的类,在这里不做分析
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
/**初始化ContextHolder,其实就是把当前的requestAttributes放到
ThreadLocal中,方便在一些没有request作为参数的方法中,
可以直接使用 RequestContextHolder.currentRequestAttributes()
取到当前的request或response对象
*/
initContextHolders(request, localeContext, requestAttributes);
try {
//重点,真正的处理交给了这个方法去执行
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (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();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
//发布事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
我们找到doService,发现它是一个FrameworkServlet的抽象方法,也就是说它希望子类DispatcherServlet去实现具体的处理过程
protected abstract void doService(HttpServletRequest request,
HttpServletResponse response) throws Exception;
在DispatcherServlet中的doService方法实现
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
//如果此次请求中包含一个uri请求,就保存request的一个快照
//方便恢复request的原始属性
Map 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("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
//设置一些全局参数给request
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()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
找到doDispatch方法,此时才是直接的开始
/**
* Process the actual dispatching to the handler.
* The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
*
All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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 {
//检查是否是Multipart请求,比如:文件上传就是一个Multipart请求
//否则返回原来的request
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//根据request去handlerMapping映射中到对应的HandlerExecutionChain
//
mappedHandler = getHandler(processedRequest);
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;
}
}
//执行链中的拦截器执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//交给适配器去解析参数等等并执行对应的方法,返回
//ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果没有view就给它一个默认的
applyDefaultViewName(processedRequest, mv);
//执行拦截器的postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//处理返回结果,这里就是把Model填充到view中
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
checkMultipart处理的内容很简单,上面已经说明,我们来看看 getHandler(processedRequest)做了哪些事件?主要是遍历handlerMappings找到匹配的执行链
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() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
HandlerMapping中的getHandler方法
/**
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@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);
}
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;
}
进入到AbstractHandlerMethodMapping的getHandlerInternal方法,先从request获取到lookupPath,相当于上面的(userControoler/getUserInfo)
/**
* Look up a handler method for the given request.
*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
/**
这里的mappingRegistry,其实就是一个映射关系注册中心,维护所有mapping与handlerMethod的映射关系
为了提供并发访问,每次都是显示的获取锁,获取后再显示的释放锁
*/
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 + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
/**
* Look up the best-matching handler method for the current request.
* If multiple matches are found, the best match is selected.
* @param lookupPath mapping lookup path within the current servlet mapping
* @param request the current request
* @return the best-matching handler method, or {@code null} if no match
* @see #handleMatch(Object, String, HttpServletRequest)
* @see #handleNoMatch(Set, String, HttpServletRequest)
*/
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List matches = new ArrayList();
//从mappingRegistry中的urllookup中获取RequestMappingInfo集合
//其实,每一个requestMapping都会被封装成RequestMappingInfo
List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//遍历所有的匹配的mappings(directPathMatches)
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 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);
//如果两个相同,则springmvc也不知道哪个是用户需要的方法了
//所以,不能存在相同的路径对应两个方法
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);
//返回最佳匹配的mapping对应的HandlerMethod
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
private void addMatchingMappings(Collection mappings, List matches, HttpServletRequest request) {
for (T mapping : mappings) {
//找到匹配的mapping加入到matchs集合中
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
Match类的结构,它其实是AbstractHandlerMethodMapping的内部类
/**
* A thin wrapper around a matched HandlerMethod and its mapping, for the purpose of
* comparing the best match with a comparator in the context of the current request.
*/
private class Match {
//Match类是AbstractHandlerMethodMapping的内部类
private final T mapping;
private final HandlerMethod handlerMethod;
public Match(T mapping, HandlerMethod handlerMethod) {
this.mapping = mapping;
this.handlerMethod = handlerMethod;
}
@Override
public String toString() {
return this.mapping.toString();
}
}
再回到AbstractHandlerMethodMapping的getHandlerInternal方法中,接下来是判断handlerMethod是否为空,如果不为空则调用createWithResolvedBean()方法,这个方法的逻辑是如果当前handlerMethod中的bean只是名称时,那么通过beanFactory获得bean的实例,再次封装成HadnerMethod对象返回。这里的bean是指方法所在的类对象,例如:上述中的userController中的getUserInfo方法,getUserInfo就是handlerMethod而userController就是上面所说的bean。
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
再回到AbstractHandlerMapping的getHandler(HttpServletRequest request)方法,接下来就是执行
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
获取执行链,进入此方法,
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//先判断是否是执行链对象,如果不是就把handler封装成一个执行链
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;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
到此时,我们已经获取到了HandlerExecutionChain执行链对象,返回到DispatcherServlet中。接下来就是需要获取执行适配器(管家)
重新回顾一下,在DispatcherServlet的doDispatch方法中,第一步是判断是否是Multipart请求,第二步就是获取执行链接对象mappedHandler。分析到此也只是完成这个方法的第二步,即通过请求的url找到对应的handlerMethod和bean对象,近而取得了执行链对象。为下一步的执行做准备。