springMVC分析-2

springMVC的請求映射

上一次分析了一下springMVC的大致流程,這次細分一下,對請求映射進行分析。
先從DispatcherServlet中的getHandler()方法分析

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;
}

可以看到這是遍歷所有的handlerMappings然后第一個返回不是NULL的handler既是,那handlerMappings包含了那些實現類呢?我們來看看initHandlerMappings這個方法

private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;//detectAllHandlerMappings 默認是trueif (this.detectAllHandlerMappings) {// 從ApplicationContext 里面獲取HandlerMapping的實現類Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);//根據Order對HandlerMappings進行排序if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {//獲取bean name是handlerMapping的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.}}//若HandlerMappings為空,則設置默認的在DispatcherServlet同級目錄下的DispatcherServlet.properties里面設置的org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterif (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}}
}

所以若我們想使用自定義的HandlerMapping 可在springMVC的xml配置文件中加上一個HandlerMapping的實現類,若是使用的是 這個進行配置的,其默認會加載RequestMappingHandlerMapping這個實現類(具體在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser見),而可以在web.xml中將detectAllHandlerMappings 設置為false,然后在springMVC.xml中配置一個name為handlerMapping的實現類。如下

// web.xml
<servlet><servlet-name>myweb</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvc.xml</param-value></init-param><!-- 不加載所有的HandlerMapping的實現類的bean --><init-param><param-name>detectAllHandlerMappings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>//mvc.xml
<bean name="handlerMapping" class="xxx具體實現類">

繼續看handlerMapping是怎么根據request獲取到HandlerExecutionChain這個包含攔截器、具體處理的controller的,在AbstractHandlerMapping中以下方法

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//獲取具體的處理類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);}//根據定義的Interceptors過濾出需要執行的攔截器,聚合成HandlerExecutionChain這個執行鏈HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//CORS跨域請求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) 這個方法,這個方法是個抽象方法,所以其實現在它的子類中,可以看出這個是一個模板模式,其在抽象類中定義出方法的骨架,而后某些方法交給子類實現,這個方法有兩個實現類,AbstractHandlerMethodMapping,AbstractUrlHandlerMapping 這兩個具體實現類,我們先看AbstractHandlerMethodMapping 這個類實現的

/*** Look up a handler method for the given request.*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {//獲取請求路徑String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);if (logger.isDebugEnabled()) {logger.debug("Looking up handler method for path " + lookupPath);}//開啟讀鎖this.mappingRegistry.acquireReadLock();try {//獲取handlerMethodHandlerMethod 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();}
}

從這里可以看出 其最后處理的是一個HandlerMethod類,我們來看看這個類的結構

public class HandlerMethod {private final Object bean;private final BeanFactory beanFactory;private final Class<?> beanType;private final Method method;private final Method bridgedMethod;private final MethodParameter[] parameters;private final HandlerMethod resolvedFromHandlerMethod;
}

可以看出其是一個聚合的類,里面包含了bean,method,故而其可以一個方法對應一個請求。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {List<Match> matches = new ArrayList<Match>();//根據請求路徑匹配List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);if (directPathMatches != null) {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<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 + "}");}}返回handlerMethodhandleMatch(bestMatch.mapping, lookupPath, request);return bestMatch.handlerMethod;}else {return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);}
}

AbstractHandlerMethodMapping 這個抽象類實現了InitializingBean接口,所以我們可以看看afterPropertiesSet()方法,其在實例化進行的初始化操作,initHandlerMethods()方法,可以看出其在初始化時,就初始化了HandlerMethod這個。

protected void initHandlerMethods() {// 獲取所有的BeanString[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));for (String name : beanNames) {//判斷這個bean是否包含Controller,和RequestMapping這兩個注解if (!name.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(name))) {//將其注冊到MappingRegistrydetectHandlerMethods(name);}}//空方法handlerMethodsInitialized(getHandlerMethods());
}

轉載于:https://www.cnblogs.com/myzhong2014/p/5310140.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/255716.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/255716.shtml
英文地址,請注明出處:http://en.pswp.cn/news/255716.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

簡單消息協議

簡單消息協議&#xff1a;定義了ROS與工業機器人之間簡單的消息協議。額外的處理程序和管理器類包含用于處理有限連接的系統。這個包是ROS-Industrial計劃的一部分。 簡單消息協議定義了ROS驅動層與機器人控制器層通信的消息結構。該消息結構符合下列要求&#xff1a; 1、結構足…

Centos安裝Vmware-Tools工具

1、打開指定的Centos虛擬機&#xff0c;點擊清單-->虛擬機-->客戶機-->安裝/升級VMware-Tools&#xff08;<u>W</u>&#xff09;&#xff1b; 2、登錄Centos會話臺&#xff0c;Applications-->Systme Tools-->Terminal&#xff1b; 3、使用“su -”…

【sqlite常用操作SQL語句】

目錄 1、創建一個新的數據表 2、在已有的數據表中增加一個新的字段&#xff08;列&#xff09; 3、 在已有的數據表中增加一條新的記錄&#xff08;行&#xff09; 1、創建一個新的數據表 "create table user(id int(11) primary key, name varchar(20))" 含義&…

perl-基礎

1、Perl 語法入門&#xff1a; 1、print 語句&#xff1a; print "Hello, world\n"; print("Hello, world\n"); 2、引號&#xff1a; Perl雙引號和單引號的區別: 雙引號可以正常解析一些轉義字符與變量&#xff0c;而單引號無法解析會原樣輸出。 3、perl數…

wdk1703+vs2015編譯的詭異問題

wdk1703vs2015編譯的詭異問題 最近將wdk升級到1703&#xff08;10.0.15063.0&#xff09;版本&#xff0c;編譯一個新建的minifiter項目居然出現了失敗 提示錯誤為 WindowsDriver.common.targets(460,5): error MSB6004: The specified task executable location "\stampi…

centos6虛擬機復制后修改網卡

方法1&#xff1a; 使用vmware創建centos6.4虛擬機&#xff0c; 創建完成后復制該虛擬機&#xff0c; 打開復制的虛擬機發現網卡名字是eth1&#xff0c;而網卡配置文件為eth0&#xff0c;mac地址變了 這時修改網卡配置文件&#xff0c; 刪除uuid&#xff0c;修改deivce為eth1&a…

【pyinstaller打包pyqt5編寫的項目為exe(脫離環境可運行)】

目錄 下載pyinstaller庫 0、pyinstaller語句介紹 1、單個py文件打包成exe 1)只有py文件 假設只有一個py文件&#xff1a;pyinstaller -F xxx.py 加上圖標&#xff1a;pyinstaller -F xxx.py -i xxx.ico 取消命令行窗口:pyinstaller -F -w xxx.py -i xxx.ico 2) 不但有py…

熔化極氣體保護電弧焊簡介

1概述 熔化極氣體保護電弧焊&#xff08;英文簡稱GMAW&#xff09;是采用連續等速送進可熔化的焊絲與被焊工件之間的電弧作為熱源來熔化焊絲和母材金屬&#xff0c;形成熔池和焊縫的焊接方法&#xff0c;如圖1所示。為了得到良好的焊縫應利用外加氣體作為電弧介質并保護熔滴、熔…

python 中cPickle學習二

寫入&#xff1a; import cPickle as p shoplistfile data.data shoplist [meili,[current_account,[100000,1222],basis_account,[5555555,888]],qinshan,[current_account,[1089000,12292],basis_account,[55555955,888]],jiayou,[current_account,[10000,12292],basis_acc…

4.0 多線程基礎篇

本文并非最終版本&#xff0c;如有更新或更正會第一時間置頂&#xff0c;聯系方式詳見文末如果覺得本文內容過長&#xff0c;請前往本人 “簡書”4.0-1.1 進程 概念 : 進程是指在系統中正在運行的一個應用程序 (操作系統中每一個 APP 就是一個進程)  性質 : 每個進程之間是獨…

【python pandas excel操作】

目錄 1、打開Excel&#xff0c;獲取不同sheet的名稱 2、獲取不同sheet的內容 3、 獲取行數以及表頭 4、對某一列的信息進行篩選 5、根據列號和索引號提取一行或者一列的數據 6、其他panda對Excel的操作 摘自&#xff1a;python對excel操作獲取某一列&#xff0c;某一行的值…

焊接機器人應用現狀及發展趨勢

據不完全統計&#xff0c;全世界在役的工業機器人中大約有將近一半的工業機器人用于各種形式的焊接加工領域&#xff0c;焊接機器人應用中最普遍的主要有兩種方式&#xff0c;即點焊和電弧焊。圖4所示是這兩種焊接機器人在工業機器人中所占的大致比例。我們所說的焊接機器人其實…

線性期望(BUPT2015校賽.F)

將整體期望分成部分期望來做。 F. network 時間限制 3000 ms 內存限制 65536 KB題目描述 A social network is a social structure made up of a set of social actors (such as individuals or organizations) and a set of the relationships between these actors. In simp…

【pyqt5學習】——進度條progressBar

# 進度條 self.progressBar.setValue(0) # 設置進度條的最小值 self.progressBar.setMaximum(100) # 設置進度條的最大值 # 設置進度條當前值 self.progressBar.setValue((int(curindex/excelNum)*100)) 常用方法 方法值說明setRangeQProgressBar.setRange(min, Max)通過 setR…

弧焊 不同氣體對焊縫的影響 100二氧化碳 15%氬氣CO2混合

Ar含量提高后&#xff0c;相比原來的100%CO2成本會提高很多。 Ar的密度比CO2小&#xff0c;焊接的焊槍必須壓的很低&#xff0c;如果焊接結構中有一些狹小區域&#xff0c;焊槍則無法到達。純CO2氣體保護焊&#xff0c;焊絲可伸出較長。 Ar屬于惰性氣體&#xff0c;焊接時…

Windows和Linux如何使用Java代碼實現關閉進程

在用selenium做自動化測試時&#xff0c;由于各種不明原因&#xff0c;有時Chrome瀏覽器會出現假死的情況&#xff0c;也就是整個瀏覽器響應超時&#xff0c;本人腳本主要部署在Windows機器上&#xff0c;所以主要以Windows為主&#xff0c;瀏覽器為Chrome,即如下圖所示 或者由…

CSS之A標簽

a標簽&#xff0c;超級鏈接 a是英語anchor錨的意思。 a標簽常用的就是三個屬性&#xff1a; 1 <a href"網址" title"懸停文本" target"_blank">超級鏈接文字</a> 頁面內的錨點&#xff0c;用name屬性或者id屬性 1 …

【pyqt5學習】——下拉框comboBox

# 向下拉框中添加選型&#xff0c;具體為在下拉框第index1個選型設置為內容name self.comboBox.addItem(name,index1) # 將下拉框中所有的選項刪除 self.comboBox.clear() # 根據索引獲取當前的下拉框內容 index self.comboBox.currentIndex() text self.comboBox.itemText(i…

安裝scapy遇到的問題

1. Mac平臺 在mac上安裝scapy可以說是困難重重&#xff0c;一來因為scapy實在有些小眾和老舊&#xff0c;再加上安裝說明文檔都是python2.5 也沒有詳細說明一些安裝問題。 折騰了大概三個小時之后終于解決了這個老大難。 注&#xff1a;我的環境為anaconda2.3 - python2.7.10 一…