欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring中HandlerMapping接口源碼詳解

 更新時(shí)間:2023年11月18日 09:48:10   作者:立小研先森  
這篇文章主要介紹了Spring中HandlerMapping接口源碼詳解,RequestMappingHandlerMapping類就是實(shí)現(xiàn)此接口并將容器中所有的控制器的RequestMappingInfo請求和HandlerMethod注冊到內(nèi)存之中,需要的朋友可以參考下

前言

實(shí)現(xiàn)HandlerMapping接口的類用來定義request請求和handler object之間的映射關(guān)系;request請求可以理解為路由url、RequestMappingInfo,handler object理解為控制器類;

RequestMappingHandlerMapping類就是實(shí)現(xiàn)此接口并將容器中所有的控制器的RequestMappingInfo請求和HandlerMethod注冊到內(nèi)存之中,方便真實(shí)的請求發(fā)送過來調(diào)用具體的控制器方法;

本文將以RequestMappingHandlerMapping為主線來講解。

接口源碼如下:

public interface HandlerMapping {
	/**
	 * 返回一個(gè)包含handler Object和所有攔截器的HandlerExecutionChain
	 */
	@Nullable
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

1.HandlerMapping的初始化

容器加載時(shí)DispatcherServlet中的初始化方法initStrategies會(huì)被調(diào)用,里面的initHandlerMappings(context)方法會(huì)被執(zhí)行,源碼如下:

  //容器中HandlerMapping接口實(shí)現(xiàn)類集合	
  @Nullable
	private List<HandlerMapping> handlerMappings;

	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		//判定是否檢測所有的HandlerMapping
		if (this.detectAllHandlerMappings) {
			//查看容器中所有的實(shí)現(xiàn)了HandlerMapping的bean
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// 使用實(shí)現(xiàn)類的order進(jìn)行優(yōu)先級排序,升序
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
        //加載缺省的HandlerMapping
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

上面的源碼是從容器中獲取HandlerMapping接口的實(shí)現(xiàn)類,其中包括RequestMappingHandlerMapping類實(shí)例,那這個(gè)類實(shí)例實(shí)在哪里加載的呢?

2.RequestMappingHandlerMapping處理reques請求

前端發(fā)送過來一個(gè)request請求首先進(jìn)入DispatcherServlet的doService方法,再進(jìn)入doDispatch方法

本文的重點(diǎn)是通過request請求如何獲取HandlerExecutionChain處理程序執(zhí)行器鏈;HandlerExecutionChain是一個(gè)很重要的類,所有的HandlerMethod最終都要包裝成HandlerExecutionChain后才可以使用;

跳出正文主題分析下HandlerExecutionChain類:

Handler execution chain, consisting of handler object and any handler interceptors. Returned by HandlerMapping’s {@link HandlerMapping#getHandler} method.

上面官方說明已經(jīng)說的很清楚了,該類包含handler object(HandlerMethod)和所有的handler interceptors;而且該類的生成只能通過HandlerMapping接口的getHandler方法,具體由AbstractHandlerMapping抽象類實(shí)現(xiàn);AbstractHandlerMapping類實(shí)現(xiàn)源碼:

	/**
	 * 根據(jù)request請求獲取HandlerExecutionChain處理程序執(zhí)行器鏈
	 * 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
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //獲取Handler object即HandlerMethod對象
		Object handler = getHandlerInternal(request);
		if (handler == null) {
      //如果沒有找到匹配的HandlerMethod對象,那么就獲取默認(rèn)的handler
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
		//根據(jù)上面獲取的handler object獲取處理程序執(zhí)行器鏈類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());
		}
		//有跨域相關(guān)配置時(shí)執(zhí)行如下代碼
		if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
			CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			config = (config != null ? config.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}

		return executionChain;
	}

看下getHandlerInternal方法如何獲取HandlerMethod對象:

	/**
	 * 通過request請求獲取對應(yīng)的HandlerMethod類
	 */
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		//獲取請求URL
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		request.setAttribute(LOOKUP_PATH, lookupPath);
		this.mappingRegistry.acquireReadLock();
		try {
      //獲取URL對應(yīng)的HandlerMethod,重點(diǎn)是我們?nèi)绾潍@取HandlerMethod對象?
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

看lookupHandlerMethod源碼:

	/**
	 * 通過URL獲取HandlerMethod對象
	 */
	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
    //通過URL獲取RequestMappingInfo集合
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
      //將RequestMappingInfo對象和HandlerMethod對象封裝到Match對象中存到matches集合
			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()) {
      //獲取集合中第一個(gè)Match對象
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
				matches.sort(comparator);
				bestMatch = matches.get(0);
				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對象
			return bestMatch.handlerMethod;
		}
		else {
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

上面的代碼有一個(gè)this.mappingRegistry.getMappingsByUrl(lookupPath)方法獲取url對應(yīng)的RequestMappingInfo對象,源碼如下:

	 //URL和RequestMappingInfo集合	
	 private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();		
		/**
		 * 返回與URL匹配的RequestMappingInfo集合
		 */
		@Nullable
		public List<T> getMappingsByUrl(String urlPath) {
			return this.urlLookup.get(urlPath);
		}

上面的源碼顯示RequestMappingInfo對象是從urlLookup集合中獲取的,那urlLookup集合中的數(shù)據(jù)又是從哪里來的呢?請看我的另外一篇文章RequestMappingHandlerMapping源碼分析。

上面代碼有一個(gè)addMatchingMappings方法,是通過這個(gè)方法獲取到的HandlerMethod對象,看下源碼:

	private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    //循環(huán)遍歷RequestMappingInfo對象
		for (T mapping : mappings) {
      //
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
        //通過this.mappingRegistry.getMappings()獲取HandlerMethod對象
				matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
			}
		}
	}
	//RequestMappingInfo和HandlerMethod集合
	private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
	/**
		 * Return all mappings and handler methods. Not thread-safe.
		 * @see #acquireReadLock()
		 */
		public Map<T, HandlerMethod> getMappings() {
			return this.mappingLookup;
		}

上面源碼獲取HandlerMethod對象實(shí)際上是從mappingLookUp集合之中獲取的,那你可能會(huì)問mappingLookup集合中的數(shù)據(jù)又是從哪里獲取到的呢?請看我的另外一篇文章RequestMappingHandlerMapping源碼分析;

回到正文,我們看下mappedHandler = getHandler(processedRequest);方法,源碼如下:

	/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
      //循環(huán)HandlerMapping實(shí)現(xiàn)類集合,其中包括RequestMappingHandlerMapping
			for (HandlerMapping mapping : this.handlerMappings) {
        //調(diào)用HandlerMapping實(shí)現(xiàn)類的getHandler方法,并獲取程序執(zhí)行器鏈類對象
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
          //如果匹配直接返回,否則返回null
					return handler;
				}
			}
		}
		return null;
	}

通過上面我們一步步的分析源碼,知道了HandlerExecutionChain處理程序執(zhí)行器鏈?zhǔn)侨绾潍@取的,HandlerExecutionChain里面包含了請求對應(yīng)的HandlerMethod對象和所有有關(guān)的連接器;

到此這篇關(guān)于Spring中HandlerMapping接口源碼詳解的文章就介紹到這了,更多相關(guān)HandlerMapping接口源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java之static關(guān)鍵字用法實(shí)例解析

    java之static關(guān)鍵字用法實(shí)例解析

    這篇文章主要介紹了java之static關(guān)鍵字用法實(shí)例解析,包括了static關(guān)鍵字的原理講解及用法分析,并附帶了實(shí)例說明,需要的朋友可以參考下
    2014-09-09
  • Java十分鐘精通異常處理機(jī)制

    Java十分鐘精通異常處理機(jī)制

    異常就是不正常,比如當(dāng)我們身體出現(xiàn)了異常我們會(huì)根據(jù)身體情況選擇喝開水、吃藥、看病、等?異常處理方法。?java異常處理機(jī)制是我們java語言使用異常處理機(jī)制為程序提供了錯(cuò)誤處理的能力,程序出現(xiàn)的錯(cuò)誤,程序可以安全的退出,以保證程序正常的運(yùn)行等
    2022-03-03
  • mybatis 如何通過resultMap 返回long

    mybatis 如何通過resultMap 返回long

    這篇文章主要介紹了mybatis 如何通過resultMap 返回long的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java?LockSupport實(shí)現(xiàn)原理示例解析

    java?LockSupport實(shí)現(xiàn)原理示例解析

    這篇文章主要為大家介紹了java?LockSupport實(shí)現(xiàn)原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 淺析Java中對稱與非對稱加密算法原理與使用

    淺析Java中對稱與非對稱加密算法原理與使用

    密碼學(xué)是研究編制密碼和破譯密碼的技術(shù)科學(xué)。這篇文章主要為大家介紹了Java中對稱與非對稱加密算法的原理與使用,感興趣的小伙伴可以了解一下
    2023-03-03
  • Spring Boot 中整合 MyBatis-Plus詳細(xì)步驟(最新推薦)

    Spring Boot 中整合 MyBatis-Plus詳細(xì)步驟(最新推薦)

    本文詳細(xì)介紹了如何在SpringBoot項(xiàng)目中整合MyBatis-Plus,包括整合步驟、基本CRUD操作、分頁查詢、批量操作、自定義SQL操作等,通過這些步驟,開發(fā)者可以快速實(shí)現(xiàn)數(shù)據(jù)庫操作,提高開發(fā)效率,感興趣的朋友一起看看吧
    2025-01-01
  • 一文看懂 Spring Aware 接口功能

    一文看懂 Spring Aware 接口功能

    Aware接口是一個(gè)空接口,可以理解為是一個(gè)標(biāo)記接口,方便在一個(gè)統(tǒng)一的方法(AbstractAutowireCapableBeanFactory.invokeAwareMethods)中進(jìn)行判斷處理賦值,在子接口寫出各自的set方法,這篇文章主要介紹了一文看懂 Spring Aware 接口功能,需要的朋友可以參考下
    2024-12-12
  • mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況

    mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況

    這篇文章主要介紹了mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • MyBatis源碼解析之Transaction事務(wù)模塊

    MyBatis源碼解析之Transaction事務(wù)模塊

    這篇文章主要介紹了MyBatis源碼解析之Transaction事務(wù)模塊,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • JAVA發(fā)送HTTP請求的多種方式詳細(xì)總結(jié)

    JAVA發(fā)送HTTP請求的多種方式詳細(xì)總結(jié)

    目前做項(xiàng)目中有一個(gè)需求是這樣的,需要通過Java發(fā)送url請求,查看該url是否有效,這時(shí)我們可以通過獲取狀態(tài)碼來判斷,下面這篇文章主要給大家介紹了關(guān)于JAVA發(fā)送HTTP請求的多種方式總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2023-01-01

最新評論