說明: 本文只對 HandlerMethod 的獲取進行分析,不對mvc的執行流程分析,全部的一塊兒源碼都是針對常見的請求(@Controller 和 @RequestMapping)java
上面已經知道了最後執行的是HandlerExecutionChain.handler,那就看看這個屬性是如何被賦值的spring
方法入口爲DispatcherServlet.doDispatch.getHandler()mvc
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. //就是在這個地方獲取的 handlerExecutionChain,也是在這裏獲取的 handlerMethod 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; } } // 攔截器的執行 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. //執行請求 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ..................................... }
上述代碼 刪除無關代碼,繼續往下:app
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { //文章開頭說了 handlerMethod 是在 handlerExceutionChain 中,因此在這個代碼裏 HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
@Override @Nullable public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //就是在這裏獲取的 handlerMethod 也就是請求的映射關係 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); } //獲取 執行鏈 把 handlerMethod 放入 HandlerExecutionChain 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 (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //根據request 獲取 請求路徑 裏面東西還挺多,很少也就是獲取路徑的 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); this.mappingRegistry.acquireReadLock(); try { //獲取 handlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }
@Nullable protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List matches = new ArrayList<>(); //這裏根據請求路徑獲取requsetMappingInfo 格式爲 [{GET /xml, produces [application/xml]}] //請求方式,請求路徑,響應類型 注意 如今這個類 是requestMappingHandlerMapping 的一個父類 // 說明 這也信息有多是在 requestMappingHandlerMapping 初始化的時候放進去的. List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { //獲取 Match 的方法 Match 中包含 HandlerMethod 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)); 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); // 發現返回的 handlerMethod 是 Match 屬性 因此咱們關注 matches 就好了 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) { //這裏又去獲取了一次 requestMappingInfo 我覺得不知道爲啥又去獲取了一次 T match = getMatchingMapping(mapping, request); if (match != null) { //這裏建立了Match 點進去發現傳了兩個參數 一個是requestMapping 一個是 HandlerMethod //如今主要看下 this.mappingRegistry.getMappings().get(mapping)) matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } }
public Map getMappings() { return this.mappingLookup; } //到這裏能夠看到了 HandlerMethod 是從mappingLookup獲取的 private final Map mappingLookup = new LinkedHashMap<>();
下面就要mappingLookup是何時被賦值的cors
mappingLookup 是 MappingRegistry 的屬性 MappingRegistry 是 AbstractHandlerMethodMapping的內部類async
思路: 在MappingRegistry.put() 的地方debug,觀察執行棧ide
重要執行節點:requestMappingHandlerMapping初始化-> afterPropertiesSet()ui
貼代碼以下:this
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { //這裏就是入口 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }@Override public void afterPropertiesSet() { //這堆配置 具體是啥我也不知道 this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setUrlPathHelper(getUrlPathHelper()); this.config.setPathMatcher(getPathMatcher()); this.config.setSuffixPatternMatch(this.useSuffixPatternMatch); this.config.setTrailingSlashMatch(this.useTrailingSlashMatch); this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch); this.config.setContentNegotiationManager(getContentNegotiationManager()); //看這裏,調用了父類的 afterPropertiesSet(); super.afterPropertiesSet();(); }@Override public void afterPropertiesSet() { //這裏 initHandlerMethods(); } //這裏 protected void initHandlerMethods() { //getCandidateBeanNames() 應該是獲取了全部的beanName for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { //就是這裏 processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } //根絕beanName處理的 protected void processCandidateBean(String beanName) { Class beanType = null; try { //獲取當前bean的class 類型 beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } //這裏 重點 isHandler() 判斷是否須要處理 if (beanType != null && isHandler(beanType)) { //假如是的話,繼續 (重點) detectHandlerMethods(beanName); } } // 看到了,條件就是 當前類是否存在 @Controller @RequestMapping 註解 protected boolean isHandler(Class beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }下面的代碼就是最後了,注意看! 下面的代碼比較繞,用的是java8的Lambda 表達式,假如對java8比較熟,看這段代碼是無壓力的 先把這幾個方法的代碼都貼出來,以下:url
protected void detectHandlerMethods(Object handler) { Class handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { //獲取當前contorller 類型 Class userType = ClassUtils.getUserClass(handlerType); // 第一步 就是這裏 執行selectMethods 這個方法 傳遞了一個行爲(lambda表達式) Map methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup) method -> { try { //第六步 return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); if (logger.isTraceEnabled()) { logger.trace(formatMappings(userType, methods)); } //第七步 methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } } public static Map selectMethods(Class targetType, final MetadataLookup metadataLookup) { final Map methodMap = new LinkedHashMap<>(); Set> handlerTypes = new LinkedHashSet<>(); Class specificHandlerType = null; //判斷是否存在代理 if (!Proxy.isProxyClass(targetType)) { specificHandlerType = ClassUtils.getUserClass(targetType); handlerTypes.add(specificHandlerType); } handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType)); //循環 第二步 目標 controller 正常狀況就一個元素 for (Class currentHandlerType : handlerTypes) { final Class targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType); // 調用 doWithMethods 第三步 ReflectionUtils.doWithMethods(currentHandlerType, method -> { //第五步 獲取到了 method Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); T result = metadataLookup.inspect(specificMethod); if (result != null) { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) { methodMap.put(specificMethod, result); } } }, ReflectionUtils.USER_DECLARED_METHODS); } return methodMap; } public static void doWithMethods(Class clazz, MethodCallback mc, @Nullable MethodFilter mf) { // Keep backing up the inheritance hierarchy. //獲取全部的方法 Method[] methods = getDeclaredMethods(clazz); for (Method method : methods) { if (mf != null && !mf.matches(method)) { continue; } try { //執行 selectMethods 方法中的 MethodFilter mf 第四步 mc.doWith(method); } catch (IllegalAccessException ex) { throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex); } } if (clazz.getSuperclass() != null) { doWithMethods(clazz.getSuperclass(), mc, mf); } else if (clazz.isInterface()) { for (Class superIfc : clazz.getInterfaces()) { doWithMethods(superIfc, mc, mf); } } } //保存對應關係入口 protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } //結束了 public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); assertUniqueMethodMapping(handlerMethod, mapping); //保存到 mappingLookup this.mappingLookup.put(mapping, handlerMethod); List directUrls = getDirectUrls(mapping); for (String url : directUrls) { //保存路徑到urlLookup this.urlLookup.add(url, mapping); } // String name = null; if (getNamingStrategy() != null) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } }總結:
- spring-ioc 初始化 requestMappingHandlerMapping 的時候 把對應關係 存放在mappingLookup
- 執行的時候 根絕請求路徑 查找urlLookup,再根據 urlLookup 的val 當作key 去 mappingLookup 中查找