對請求進行處理html
處理返回值java
封裝了參數信息:參數的的索引位置,類型,註解,參數名等信息git
各類condition,其中RequestMappingInfo相似代理類,相似condition集合。web
AbstractHandlerMethodMapping implements InitializingBeanspring
初始化階段會執行afterPropertiesSet() 方法。mvc
@Override public void afterPropertiesSet() { initHandlerMethods(); }
從ApplicationContext中檢測,註冊HandlerMethodsapp
/** * Scan beans in the ApplicationContext, detect and register handler methods. * @see #isHandler(Class) * @see #getMappingForMethod(Method, Class) * @see #handlerMethodsInitialized(Map) */ protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } //找出容器中的全部類。 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { //排除scopedTarget.開頭的bean if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { beanType = getApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } //isHandler()檢測是不是handler,模版方法 //RequestMappingHandlerMapping.isHandler() 判斷是不是@controller 或者 @RequestMapping if (beanType != null && isHandler(beanType)) { //查找HandlerMethods detectHandlerMethods(beanName); } } } handlerMethodsInitialized(getHandlerMethods()); }
/** * Look for handler methods in a handler. * @param handler the bean name of a handler or a handler instance */ //傳進來的是beanName protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); //針對CGLIB生成的子類,找到真正用戶定義的類型userType final Class<?> userType = ClassUtils.getUserClass(handlerType); //從Class中獲取<Method,RequestMappingInfo> Map<Method, T> methods = MethodIntrospector.selectMethods(userType, new MethodIntrospector.MetadataLookup<T>() { @Override public T inspect(Method method) { try { //RequestMappingHandlerMapping.getMappingForMethod(),構造getMappingForMethod // return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } } }); if (logger.isDebugEnabled()) { logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); } for (Map.Entry<Method, T> entry : methods.entrySet()) { //判斷Method是否可調用(不是private方法) Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); //RequestMappingInfo(方法上的信息) T mapping = entry.getValue(); //註冊到AbstractHandlerMethodMapping.MappingRegistry屬性中。 registerHandlerMethod(handler, invocableMethod, mapping); } }
用來創造RequestMappingInfo的cors
/** * Uses method and type-level @{@link RequestMapping} annotations to create * the RequestMappingInfo. * @return the created RequestMappingInfo, or {@code null} if the method * does not have a {@code @RequestMapping} annotation. * @see #getCustomMethodCondition(Method) * @see #getCustomTypeCondition(Class) */ @Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { //先從method中獲取info RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { //不爲空,再從Class中獲取Info RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { //最後combine info = typeInfo.combine(info); } } return info; }
/** * Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)}, * supplying the appropriate custom {@link RequestCondition} depending on whether * the supplied {@code annotatedElement} is a class or method. * @see #getCustomTypeCondition(Class) * @see #getCustomMethodCondition(Method) */ //獲取RequestMappingInfo private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); //獲取自定義Condition,能夠自定義,參見https://app.yinxiang.com/shard/s47/nl/20202808/83224da8-631d-4d1a-a586-9ac56564d74b RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); //主要就是將@RequestMapping中大部分信息設置到RequestMappingInfo中 //而且構造各類condition, return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); }
設計到的MappingRegistry中的Mapide
//<RequestMappingInfo,MappingRegistration> private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>(); //<RequestMappingInfo,HandlerMethod> private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>(); //<url,RequestMappingInfo> private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>(); //RequestMappingInfo.Name或HandlerMethod的name, List<HandlerMethod> private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>(); private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();
//註冊mapping是RequestMappingInfo public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { //構造HandlerMethod HandlerMethod handlerMethod = createHandlerMethod(handler, method); //確認惟一的mapping assertUniqueMethodMapping(handlerMethod, mapping); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod); } //放入mappingLookup中,<RequestMappingInfo,HandlerMethod> this.mappingLookup.put(mapping, handlerMethod); //獲取url,從RequestMappingInfo的PatternsCondition中獲取。 List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { //<url,RequestMappingInfo> this.urlLookup.add(url, mapping); } String name = null; if (getNamingStrategy() != null) { //命名策略 // For example "TC#getFoo" * for a class named TestController with method getFoo. //RequestMappingInfo的name不爲空則返回其name,若是爲空,按照命名策略定義一個名字,例如「TC#foo」 name = getNamingStrategy().getName(handlerMethod, mapping); //this.nameLookup.put(name, List<HandlerMethod>); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } //<RequestMappingInfo,MappingRegistration> this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } }
/** * Creates {@link RequestMappingInfo} instances from type and method-level * {@link RequestMapping @RequestMapping} annotations in * {@link Controller @Controller} classes. */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response){ ... mappedHandler = getHandler(processedRequest); ... }
getHandler中使用DispatcherServlet 中配置的 List<HandlerMapping> handlerMappings;
來獲取handlerui
//org.springframework.web.servlet.DispatcherServlet#getHandler HandlerExecutionChain handler = hm.getHandler(request);
HandlerMapping的getHandler()方法由抽象類AbstractHandlerMapping實現
@Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //根據request獲取handler,此處handler是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 = 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; }
getHandlerInternal(request);爲AbstractHandlerMapping的抽象方法
AbstractHandlerMapping類繼承關係
AbstractHandlerMethodMapping 和 AbstractUrlHandlerMapping
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //獲取path,從request獲取contextPath + RequestUri + RemainingPath /** * Return the path within the servlet mapping for the given request, * i.e. the part of the request's URL beyond the part that called the servlet, * or "" if the whole URL has been used to identify the servlet. * <p>Detects include request URL if called within a RequestDispatcher include. * <p>E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a". * <p>E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a". * <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a". * <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "". * <p>E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "". * @param request current HTTP request * @return the path within the servlet mapping, or "" */ String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } //加讀鎖 this.mappingRegistry.acquireReadLock(); try { //根據path找HandlerMethod // 從mappingRegistry.urlLookup()中根據url找到對應的List<RequestMappingInfo> //遍歷 RequestMappingInfo,RequestMappingInfo中有各類condition,根據requst看各個RequestMappingInfo與requst是否匹配,匹配的話構造一個新的RequestMappingInfo返回。 //根據新構造的RequestMappingInfo和從mappingRegistry.getMappings中根據request獲取的HandleMehtod,構造Match對象,並加入到List<Match>中。 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(); } }
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); //url -> RequestMappingInfo (從urlLookup中),多值map List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { //directPathMatche就是RequestMappingInfo //(directPathMatche,request) -> new RequestMappingInfo() //檢測是否全部的condition 與提供的request匹配。 //mappingRegistry.mappingLookup().get(directPathMatche) -> HandleMethod (this.mappingLookup) //(new RequestMappingInfo(),HandleMethod) -> Match -> List<Match> 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()) { //構造比較器,比較方法最終調用各個condition的compare方法 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 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.handlerMethod.getMethod(); throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } //將匹配的LookupPath放入request中?有啥用? handleMatch(bestMatch.mapping, lookupPath, request); //Match中有HandlerMethod,返回對應的HandlerMethod return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } }
/** * Build a {@link HandlerExecutionChain} for the given handler, including * applicable interceptors. * <p>The default implementation builds a standard {@link HandlerExecutionChain} * with the given handler, the handler mapping's common interceptors, and any * {@link MappedInterceptor}s matching to the current request URL. Interceptors * are added in the order they were registered. Subclasses may override this * in order to extend/rearrange the list of interceptors. * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a * pre-built {@link HandlerExecutionChain}. This method should handle those * two cases explicitly, either building a new {@link HandlerExecutionChain} * or extending the existing chain. * <p>For simply adding an interceptor in a custom subclass, consider calling * {@code super.getHandlerExecutionChain(handler, request)} and invoking * {@link HandlerExecutionChain#addInterceptor} on the returned chain object. * @param handler the resolved handler instance (never {@code null}) * @param request current HTTP request * @return the HandlerExecutionChain (never {@code null}) * @see #getAdaptedInterceptors() */ //主要就是給handler設置interceptor //傳入的handler多是handler(HandlerMethod)或者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; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
<mvc:resources location="/static/" mapping="/static/**"/>
Spring 使用 ResourcesBeanDefinitionParser 解析 xml 實例化SimpleUrlHandlerMapping,註冊handlerMethod爲ResourceHttpRequestHandler。
ResourceHttpRequestHandler進行handleRequest的時候,直接輸出資源文件的文本內容。