最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringMVC中的HandlerMapping詳解

 更新時間:2023年09月09日 08:50:32   作者:果子爸聊技術(shù)  
這篇文章主要介紹了SpringMVC中的HandlerMapping詳解,HandlerMapping是請求映射處理器,也就是通過請求的url找到對應(yīng)的邏輯處理單元(Controller),注意這里只是建立請求與Controller的映射關(guān)系,最終的處理是通過HandlerAdapt來進(jìn)行處理的,需要的朋友可以參考下

1.簡介

在SpringMVC請求流程中我們可以看出,HandlerMapping是請求映射處理器,也就是通過請求的url找到對應(yīng)的邏輯處理單元(Controller),注意這里只是建立請求與Controller的映射關(guān)系,最終的處理是通過HandlerAdapt來進(jìn)行處理的。

2.初始化分析

在初識DispatcherServlet中提到過DispatcherServlet的初始化中會調(diào)用initStrategies()方法,實(shí)際上HandlerMapping的初始化是調(diào)用initStrategies()中的

initHandlerMappings(context);

從方法名稱就可以看出來是進(jìn)行HandlerMapping的初始化。下面來看一下具體的源碼:

/**
	 * Initialize the HandlerMappings used by this class.
	 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
	 * we default to BeanNameUrlHandlerMapping.
	 */
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		if (this.detectAllHandlerMappings) {
			//從ApplicationContext(包括繼承來的上下文)中獲取所有的HandlerMapping
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
			   //從ApplicationContext中獲取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) {
		   //若上下文中沒有handlerMapping,就使用Spring默認(rèn)的handlerMapping
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

從以上初始化源碼中我們可以看出handlerMapping的初始化:

1.通過detectAllHandlerMappings參數(shù)來控制是僅從當(dāng)前context中獲取handlerMapping,還是需要從當(dāng)前+繼承來的context中獲取所有的handlerMapping

2.若context中沒有獲取到handlerMapping,SpringMVC提供了默認(rèn)的handlerMapping來處理請求
下面我們來看一下,默認(rèn)的handlerMapping

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		//關(guān)鍵是這句,從默認(rèn)配置中獲取handlerMapping
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<T>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Error loading DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}

關(guān)鍵是defaultStrategies,它是個Properties對象,用來存儲讀取到的SpringMVC默認(rèn)的配置,那SpringMVC的默認(rèn)配置是在哪里定義的呢?在DispatcherServlet中有這么一段:

static {
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}

這段就是讀取默認(rèn)配置的代碼,它從DispatcherServlet同級目錄中的DispatcherServlet.properties文件中讀到相關(guān)配置,文件內(nèi)容如下:

.
.****省略其他配置*****
.
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

從默認(rèn)配置中可以明顯看出,SpringMVC默認(rèn)提供了兩種HandlerMapping:BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping

3.請求處理分析

HandlerMapping是請求處理的映射器,那是它是如何做請求映射處理的呢?下面我們來看一下DispatcherServlet中對請求映射的處理。 DispatcherServlet的doDispatch方法中有這么一段:

mappedHandler = getHandler(processedRequest);

這一段就是HandlerMapping對請求映射的處理,返回一個Handler執(zhí)行鏈(HandlerExecutionChain)

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;
	}
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //根據(jù)reuqest中的請求url獲取handler
		Object handler = getHandlerInternal(request);
		if (handler == null) {
		   //若沒有獲取到handler,就獲取默認(rèn)的handler
			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;
	}

4.請求是如何找到Controller的

我們知道Web容器在啟動的時候,會自動進(jìn)行Servlet的初始化,由Servlet的初始化來驅(qū)動Spring容器(ApplicationContext)的初始化,在Spring容器初始化的時候,會把標(biāo)注為@Controller的類作為Bean加載到Spring容器中,如下圖方法的調(diào)用??梢钥闯龀跏蓟^程

初始化過程

//org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping
protected void detectHandlers() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
		}
		//獲取Spring容器中的BeanName
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));
		// 遍歷Spring容器中的Bean
		for (String beanName : beanNames) {
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// 將RequestMapping中的url與beanName建立關(guān)系,注冊到handlerMap中
				registerHandler(urls, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
				}
			}
		}
	}
//注冊Handler
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		Assert.notNull(urlPath, "URL path must not be null");
		Assert.notNull(handler, "Handler object must not be null");
		Object resolvedHandler = handler;
		// Eagerly resolve handler if referencing singleton via name.
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			if (getApplicationContext().isSingleton(handlerName)) {
				resolvedHandler = getApplicationContext().getBean(handlerName);
			}
		}
		Object mappedHandler = this.handlerMap.get(urlPath);
		if (mappedHandler != null) {
			if (mappedHandler != resolvedHandler) {
				throw new IllegalStateException(
						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
			}
		}
		else {
			if (urlPath.equals("/")) {
				if (logger.isInfoEnabled()) {
					logger.info("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
				if (logger.isInfoEnabled()) {
					logger.info("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			else {
			    //建立url與beanName的關(guān)系,方便后面通過請求url找到對應(yīng)的Bean
				this.handlerMap.put(urlPath, resolvedHandler);
				if (logger.isInfoEnabled()) {
					logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

讓我們再回到HandlerMapping的處理,當(dāng)請求到來時,會先到DispatcherServlet,然后會執(zhí)行HandlerMapping相關(guān)方法,下面我們再次看一下

//DispatcherServlet
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() + "'");
			}
			//獲取Handler
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}
//org.springframework.web.servlet.handler.AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //通過請求中的url拿到之前初始化時handlerMap中的bean,并返回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;
	}
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
         //從request中拿到請求的url
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		//通過請求的url拿到handler,具體怎么拿的,請往下看lookupHandler()方法的實(shí)現(xiàn)
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = getApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		if (handler != null && logger.isDebugEnabled()) {
			logger.debug("Mapping [" + lookupPath + "] to " + handler);
		}
		else if (handler == null && logger.isTraceEnabled()) {
			logger.trace("No handler mapping found for [" + lookupPath + "]");
		}
		return handler;
	}
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// 從handlerMap中拿handler,有沒有很熟悉的感覺,對,前面初始化時我們把url與BeanName的對應(yīng)關(guān)系放到handlerMap中,現(xiàn)在取出Handler,實(shí)際上取出來的就是beanName,此時通過請求的url就拿到了對應(yīng)的beanName,handlerMapping也光榮的完成了它的任務(wù)
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				//通過beanName從Spring容器中拿到Bean對象
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}
		// Pattern match?
		List<String> matchingPatterns = new ArrayList<String>();
		for (String registeredPattern : this.handlerMap.keySet()) {
			if (getPathMatcher().match(registeredPattern, urlPath)) {
				matchingPatterns.add(registeredPattern);
			}
			else if (useTrailingSlashMatch()) {
				if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
					matchingPatterns.add(registeredPattern +"/");
				}
			}
		}
		String bestPatternMatch = null;
		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
		if (!matchingPatterns.isEmpty()) {
			Collections.sort(matchingPatterns, patternComparator);
			if (logger.isDebugEnabled()) {
				logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
			}
			bestPatternMatch = matchingPatterns.get(0);
		}
		if (bestPatternMatch != null) {
			handler = this.handlerMap.get(bestPatternMatch);
			if (handler == null) {
				Assert.isTrue(bestPatternMatch.endsWith("/"));
				handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
			}
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
			// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
			// for all of them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
					Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
					uriTemplateVariables.putAll(decodedVars);
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
			}
			return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
		}
		// No handler found...
		return null;
	}

總結(jié)

1、HandlerMapping的任務(wù)就是建立url與Bean(Controller)的對應(yīng)關(guān)系,并將對應(yīng)關(guān)系保存在handlerMap中

2、對應(yīng)關(guān)系在HandlerMapping初始化的時候就已經(jīng)建立好了

3、當(dāng)請求到來時,會通過DispatcherServlet找到HandlerMapping,然后通過請求的url在handlerMap中找到對應(yīng)的Controller,至此HandlerMapping的任務(wù)完成了,下一步就是HandlerAdapter出場了

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

相關(guān)文章

  • springboot使用webservice發(fā)布和調(diào)用接口的實(shí)例詳解

    springboot使用webservice發(fā)布和調(diào)用接口的實(shí)例詳解

    本文介紹了如何在Springboot中使用webservice發(fā)布和調(diào)用接口,涵蓋了必要的依賴添加和代碼示例,文中提供了服務(wù)端和客戶端的實(shí)現(xiàn)方法,以及如何設(shè)置端口和服務(wù)地址,幫助讀者更好地理解和應(yīng)用Springboot結(jié)合webservice的技術(shù)
    2024-10-10
  • Java 基礎(chǔ)之事務(wù)詳細(xì)介紹

    Java 基礎(chǔ)之事務(wù)詳細(xì)介紹

    這篇文章主要介紹了Java 基礎(chǔ)之事務(wù)詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • JDK14的新特性NullPointerExceptions的使用

    JDK14的新特性NullPointerExceptions的使用

    這篇文章主要介紹了JDK14的新特性NullPointerExceptions的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 詳解Java并發(fā)編程中的優(yōu)先級隊(duì)列PriorityBlockingQueue

    詳解Java并發(fā)編程中的優(yōu)先級隊(duì)列PriorityBlockingQueue

    PriorityBlockingQueue是Java中實(shí)現(xiàn)了堆數(shù)據(jù)結(jié)構(gòu)的線程安全的有界阻塞隊(duì)列。本文將會深入解讀PriorityBlockingQueue的源碼實(shí)現(xiàn),感興趣的可以了解一下
    2023-05-05
  • 通過實(shí)例學(xué)習(xí)Java集合框架HashSet

    通過實(shí)例學(xué)習(xí)Java集合框架HashSet

    這篇文章主要介紹了通過實(shí)例學(xué)習(xí)Java集合框架HashSet,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • Java初學(xué)者入門之繼承和多態(tài)

    Java初學(xué)者入門之繼承和多態(tài)

    Java 面向?qū)ο缶幊逃腥筇匦裕悍庋b、繼承、多態(tài),學(xué)好繼承和多態(tài)是面向?qū)ο箝_發(fā)語言中非常重要的一個環(huán)節(jié),這篇文章主要給大家介紹了關(guān)于Java初學(xué)者入門之繼承和多態(tài)的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • @RequestController之?dāng)?shù)據(jù)源與連接池使用及說明

    @RequestController之?dāng)?shù)據(jù)源與連接池使用及說明

    文章總結(jié):介紹了Spring MVC中的@Controller和@ResponseBody注解以及@RequestMapping注解的使用方法,詳細(xì)講解了數(shù)據(jù)源、連接池的概念及其在Java項(xiàng)目中的應(yīng)用,包括JNDI、DBCP、C3P0和Druid等連接池的配置和特點(diǎn)
    2026-01-01
  • java 自定義類比較器代碼

    java 自定義類比較器代碼

    這篇文章主要介紹了java 自定義類比較器代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java提示解析時已到達(dá)文件結(jié)尾的解決方法

    Java提示解析時已到達(dá)文件結(jié)尾的解決方法

    在本篇文章中小編給大家分享了關(guān)于Java提示解析時已到達(dá)文件結(jié)尾的解決方法,需要的朋友們學(xué)習(xí)下。
    2019-07-07
  • Java中valueOf和parseInt的區(qū)別詳解

    Java中valueOf和parseInt的區(qū)別詳解

    這篇文章主要介紹了Java中valueOf和parseInt的區(qū)別詳解,在編程中,遇到類型轉(zhuǎn)換,好像會經(jīng)常用到 parseInt 和 valueOf,當(dāng)然這里只拿 Integer 類型進(jìn)行陳述,其他類型也是雷同的,需要的朋友可以參考下
    2024-01-01

最新評論

都兰县| 仪陇县| 邯郸县| 将乐县| 华池县| 清丰县| 呼图壁县| 牙克石市| 吉水县| 武城县| 温宿县| 海晏县| 原平市| 竹北市| 泸水县| 辰溪县| 崇义县| 霍州市| 双峰县| 博客| 仙桃市| 连山| 嘉定区| 旅游| 铅山县| 武川县| 琼中| 通榆县| 会宁县| 云和县| 定结县| 乐陵市| 林州市| 上林县| 鄂尔多斯市| 玉门市| 望奎县| 凯里市| 特克斯县| 德惠市| 烟台市|