docs/Spring全家桶/SpringMVC源码分析/请求执行流程(一)之获取Handler.md
һƪǷ RequestMapping ʼ̣Ľ spring mvc ִ̡
spring mvc ֮ DispatcherServlet ʼһУ servlet DispatcherServlet һϵгʼ̣ĽΧ servlet springmvc ̡
ڷ DispatcherServlet ǰҪع servlet ִڡ
ʵԶ servlet ʱһʵ HttpServletȻд doGet(xxx)``doPost() ʵ servlet Ϊ HttpServlet#service(ServletRequest, ServletResponse)
public abstract class HttpServlet extends GenericServlet {
...
// ˲ת
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
// ﴦת
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException(lStrings.getString("http.non_http"));
}
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 {
...
doGet(req, resp);
}
} 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 {
// ûжӦķ
...
}
}
}
servlet Դ룬Ƚϼص㲿ֶעͣҪٴǿ£
HttpServlet#service(ServletRequest, ServletResponse)HttpServlet#service(HttpServletRequest, HttpServletResponse) ҵӦĴִУһ˵Զ servletֻҪд doGet(xxx)``doPost(xxx) ȷɡ̴£
DispatcherServlet ĸࣺFrameworkServlet˽ servlet ں͵÷һòˣFrameworkServlet``FrameworkServlet HttpServlet ࣬ʵ HttpServlet ĸ doXxx()ͬʱҲʵ service(HttpServletRequest, HttpServletResponse)
/**
* FrameworkServlet̳HttpServletBeanHttpServletBean̳HttpServlet
* FrameworkServletҲHttpServlet
*/
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
@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);
}
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
// GET/POST/PUT/DELETE ǻøķ
super.service(request, response);
}
}
}
ԿϴУһij൱ߣFrameworkServlet#processRequest doXxx(xxx) service(xxx) processRequest(xxx)Ǿʲô
FrameworkServlet#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(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);
}
}
Ȼе㳤̹ϵصֻмУ
...
try {
// Ĵ
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
...
ɴ˿Կʵʴķ FrameworkServlet#doService СFrameworkServlet#doService Ǹ
protected abstract void doService(HttpServletRequest request,
HttpServletResponse response) throws Exception;
ʵ࣬Ҳ DispatcherServlet#doService С
DispatcherServlet#doServiceDispatcherServlet#doService ɶ£
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void doService(HttpServletRequest request,
HttpServletResponse response) throws Exception {
logRequest(request);
// ʡһ
...
try {
// Ĵ
doDispatch(request, response);
}
finally {
...
}
}
}
˷Ҳûʲôʵֻǵһ doDispatch ȻûˡʵϣDispatcherServlet#doDispatch մص
һܽ DispatcherServlet ̣
DispatcherServlet#doDispatchһڵǷ springmvc ķ DispatcherServlet#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 {
//ļϴ
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 1\. ȡӦhandler,
// HandlerаشControllerеķһHandlerInterceptor
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// ûҵ404
noHandlerFound(processedRequest, response);
return;
}
// 2\. ȡӦhandlerAdapter handler(xxx)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// last-modified
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;
}
}
// 3\. spring, HandlerInterceptor#preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4\. ͨȡhandlerAdapterhandle
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// ûзͼʹĬϵ
applyDefaultViewName(processedRequest, mv);
// 5\. ִ HandlerInterceptor#postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 6\. ؽȾͼԼִ HandlerInterceptor#afterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (...) {
// ִ HandlerInterceptor#afterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
// صִз AsyncHandlerInterceptor#afterConcurrentHandlingStarted
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
ڵ㳤̺springmvc ̶ˣѹؼչʾ£
HandlerExecutionChain, ȡ HandlerExecutionChain аشController еķһ HandlerInterceptorhandlerAdapterö handler(xxx)HandlerInterceptor#preHandlehandlerAdapter handle(xxx)HandlerInterceptor#postHandleHandlerInterceptor#afterCompletionܵˣ̷ˡ
HandlerExecutionChainȡ HandlerExecutionChain ķ DispatcherServlet#getHandler У
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// еhandlerMapping
// handlerMapping WebMvcConfigurationSupport
for (HandlerMapping mapping : this.handlerMappings) {
// þhandlerĸhandlerֱܹӷ
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
handlerMappings WebMvcConfigurationSupport ģһķܲο springmvc demo @EnableWebMvc עһģ handlerMappings Щɶ
RequestMappingHandlerMapping ŴѾϤ @Controller/@RequestMapping ʽʵֵ controllerӦ HandlerMapping RequestMappingHandlerMapping HandlerMappingֱӦͬʽʵֵ controllerһ㣬ȤСаٶȣͲչˡ
Ǽ AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 1\. þʵȥȡhandler
Object handler = getHandlerInternal(request);
// ΪʹĬϵ
if (handler == null) {
handler = getDefaultHandler();
}
// ûĬϵķؿ
if (handler == null) {
return null;
}
// ͨBeanNameȥȡhandler
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 2\. ȡ executionChainʵҵ uri Ӧ Interceptors,
// ȻҵhandlerһװHandlerExecutionChain
// InterceptorsҲWebMvcConfigurationSupportõ
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 3\. ·صãCorsHandlerExecutionChain
// ԿνcorsãҲʵֵ
if (hasCorsConfigurationSource(handler)) {
CorsConfiguration config = (this.corsConfigurationSource != null
? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
// صӵ InterceptorsӵListĵһ
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
Ҫ£
executionChain executionChain ˰һ handler ⣬ uri Ӧ InterceptorsȡΪȡе Interceptors ã WebMvcConfigurationSupport õģһж uri Ƿ Interceptor uri ãexecutionChain е Interceptors бĵһλţûcors Ҳ WebMvcConfigurationSupport õġHandlerMethodǽ getHandlerInternal(xxx)
AbstractHandlerMethodMapping#getHandlerInternal
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// ȡurl
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// uriӦhandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// handlerMethodΪգ´һHandlerMethod
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
ﻹǵ lookupHandlerMethod(xxx) handlerMethod
AbstractHandlerMethodMapping#lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request)
throws Exception {
List<Match> matches = new ArrayList<>();
// ȴurlLookupңurlLookupһmapkeyurlvalueLinkedList<RequestMappingInfo>
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// ڷصһ listеƥĽһmatches
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// ͨurlûҵе mappings ƥ䣬ƥ /test/{name} url
// mappingsҲһmapkeyRequestMappingInfo valueHandlerMethod
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// ҵƥmapping,ӦHandlerMethod
// ȽϹ RequestMappingInfo#compareTo
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
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. .,m.bvc .getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(...);
}
}W
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);
}
}
Ǵ handler ĻȡˡĻȡΪ裺
urlLookup ңurlLookup һ map``key url``value LinkedList<RequestMappingInfo> map.get(xxx)url ûҵе mappings ƥ䣬ƥ /test/{name} url``mappings Ҳһ map``key RequestMappingInfo value HandlerMethodHandlerMethod RequestMappingInfo#compareTo ṩķҵѵ RequestMappingInfo Ӧ HandlerMethodmappings ҵƥ RequestMappingInfo ģ
AbstractHandlerMethodMapping#addMatchingMappings
private void addMatchingMappings(Collection<T> mappings, List<Match> matches,
HttpServletRequest request) {
for (T mapping : mappings) {
// ƥҵз mappings
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
շƥĴ RequestMappingInfo#getMatchingCondition УRequestMappingInfo һ compareTo Ҳһ鿴£
RequestMappingInfo
/**
* ƥ
* ֱƥ (get,post)ͷ
*/
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
if (methods == null) {
return null;
}
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
if (params == null) {
return null;
}
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
if (headers == null) {
return null;
}
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
if (consumes == null) {
return null;
}
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
if (produces == null) {
return null;
}
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
}
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
if (custom == null) {
return null;
}
return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}
/**
* ȽϹҵƥ
* ֱȽ (get,post)ͷ
*/
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
int result;
if (HttpMethod.HEAD.matches(request.getMethod())) {
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
if (result != 0) {
return result;
}
}
result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
if (result != 0) {
return result;
}
result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
if (result != 0) {
return result;
}
result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
if (result != 0) {
return result;
}
result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
if (result != 0) {
return result;
}
result = this.producesCondition.compareTo(other.getProducesCondition(), request);
if (result != 0) {
return result;
}
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
if (result != 0) {
return result;
}
result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
if (result != 0) {
return result;
}
return 0;
}
ƥ䣬DZȽϣ (get,post )ͷһһд
Ǿ springmvc ҵ HandlerMethod ˡ
Interceptorsǻص AbstractHandlerMapping#getHandlerλȡ Interceptor ģ
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
...
// 2\. ȡ executionChainʵҵ uri Ӧ Interceptors,
// ȻҵhandlerһװHandlerExecutionChain
// InterceptorsҲWebMvcConfigurationSupportõ
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
...
return executionChain;
}
getHandlerExecutionChain
AbstractHandlerMapping#getHandlerExecutionChain
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);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// жϵǰ·Ƿinterceptorõ·
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
ȽϼѾڴעͣͲ˵
õĴ
public final HandlerExecutionChain getHandler(HttpServletRequest request)
throws Exception {
...
// 3\. ·صãCorsHandlerExecutionChain
// ԿνcorsãҲʵֵ
if (hasCorsConfigurationSource(handler)) {
// ȡ
CorsConfiguration config = (this.corsConfigurationSource != null
? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
// صӵ InterceptorsӵListĵһ
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
Ҳ WebMvcConfigurationSupport ã
protected void addCorsMappings(CorsRegistry registry) {
...
}
springmvc ȡúӵ HandlerExecutionChain У
# AbstractHandlerMapping#getCorsHandlerExecutionChain
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
}
else {
// ӵInterceptorsλ
chain.addInterceptor(0, new CorsInterceptor(config));
}
return chain;
}
# HandlerExecutionChain#addInterceptor(int, HandlerInterceptor)
public void addInterceptor(int index, HandlerInterceptor interceptor) {
// ʵDzһlist
initInterceptorList().add(index, interceptor);
}
HandlerExecutionChain Уһ List InterceptorȡĿãӵ List index=0 λá
handler ͻȡˣ handler ֣
HandlerMethod: ķڱֻ @Controller ʽ controllerԼΪ @RequestMapping עķList<Interceptor>: пãôû List ĵһλHandlerAdapterٻص DispatcherServlet#doDispatch ȡ HandlerAdapter ķ
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
...
// 2\. ȡӦhandlerAdapter handler(xxx)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
getHandlerAdapter(xxx)
DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// handlerAdapters beanҲWebMvcConfigurationSupport
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// ͬhandlerAdapterжϷͬ
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException(...);
}
Կҵǰе adapterȻжǷܴǰ handlerе adapter £
жǷܴǰ handler ģǿһ handler AbstractHandlerMethodAdapter#supports
AbstractHandlerMethodAdapter#supports
@Override
public final boolean supports(Object handler) {
// жhandlerǷΪHandlerMethodʵ
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
һжϣȻٵ supportsInternal
RequestMappingHandlerAdapter#supportsInternal
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
ֱӷ true, ڿɼ handler ʵ HandlerMethodôͻ᷵ RequestMappingHandlerAdapter.
һҵ adapter Ϊ RequestMappingHandlerAdapter adapter ʲôأƪľȵˣʣµƪ¼
ԭӣhttps://my.oschina.net/funcy/blog/4717420 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע