研究 Spring MVC 将請求分發到 Spring 依賴注入的類執行個體
太陽火神的美麗人生 (http://blog.csdn.net/opengl_es)
本文遵循“署名-非商業用途-保持一緻”創作公用協定
轉載請保留此句:太陽火神的美麗人生 - 本部落格專注于 靈活開發及移動和物聯裝置研究:iOS、Android、Html5、Arduino、pcDuino,否則,出自本部落格的文章拒絕轉載或再轉載,謝謝合作。
一上午時間,碰了 N 個釘子,不斷地把釘子撥掉,記錄一下選擇的工具和方法:
1、首先 Spring Mvc 架構的下載下傳,那麼有三個包是必不可少的:
spring-webmvc-3.2.9.RELEASE.jar
spring-web-3.2.9.RELEASE.jar
spring-core-3.2.9.RELEASE.jar
還有一個,暫不考慮 ;
這些包,之前從 Spring 官網下載下傳,那叫一個費勁兒,隻能在網上下載下傳一些别人的示例,其中帶的包來用。其實是示例為主,包為輔

,從頭學起就得這樣啦。
從以下位址可以搜到想要的 Jar 包
http://mvnrepository.com/
我們輸入 spring-webmvc-3.2.9.RELEASE.jar 點按搜尋,得到下圖内容:
點第一條 Spring Web MVC ,轉入到如下頁面内容部分:
點按其中的 3.2.9 RELEASE ,終于周折到目标位置了:
點那個 Download(JAR)(623 KB)就可以下載下傳了。
該頁面,往下滾動,找到如下内容部分:
除了 Java Spec 和 JSP Tag Library ,是 J2EE 自帶的庫外,其它的可能都要下來試一試了,不過并不是所有的都是必須的,僅當你用到了 Spring 提供的該項功能,而該項功能是依托于以上所列特定包時,才需要。
這些裡面已經包含了上面所提到的所有 Jar 了,真是了不起的 Maven,不過我并沒有把工程轉成 Maven 管理,老程式員嘛,N年前用過的,Maven 還沒有出來,不太習慣,不過要說它确實不錯。但目前網上評論,都是它有點複雜,而 Gradle 又成為了熱點,這個我相信,Grails 的興起足以說明。
2、在從頭配置的過程中,按網上的例子,建立了動态 Web 工程,并在 web.xml 中添加了 Spring 的上下文參數以指定 Spring 的配置檔案位置;添加 Spring 的上下文加載監聽器,這樣 Spring 就配置完了,Spring 有三種加載方式,在網上看過了 N 篇,從遠及近或從近及遠,都說 Servlet 的方式已經不支援?插件方式對于 structs 2 也不支援了?不知道弄沒弄混,最後,隻有監聽器的加載方式依然綠樹常青,也許有它的道理吧,不得而知,待俺把門入了,再研究。
3、配置 SpringMVC 的分發器 Servlet 及映射,這個,俺把十年前的 Java Web 書從書堆裡扒啦出來,一頓翻,終于又熟悉了,這個也怪,我記憶猶新,當年看的時侯,确實隻能記住,确看不懂,而現在是從另一個角度和方向來看,就不存在懂不懂的問題,而成為了一個參考書,這裡要這樣寫,那裡要那樣寫,最後配成了通路這個位址,就轉到同名的那個 Servlet 被調用,高度不同,看問題的角度誠然是不同的,當然了,在 Java Web 面向俺高度很低,但俺已經養成,俺很低的時侯,我會把它放到地坑裡去看它,哈哈,說笑。。。
這樣配完,預設 Spring MVC 找給它配置的對應的 Servlet 名開頭,後跟 -servlet.xml 的配置檔案加載。
是的,就是在這裡糾結了 N 多時侯,正常在其配置檔案中配置了控制器的搜尋包路徑,那麼添加了注解 @Controller 的類都會被搜尋到,再根據這些類中的方法前的注解 @RequestMapping(method = RequestMethod.GET) 來找對應的映射,這些都不用在 XML 中配置了,據說這是 Spring MVC 現在比較流行的原因,這樣性能沒有瓶頸,而 Structs 的團隊也承認 XML 配置檔案的方式導緻性能問題,這些說法,俺也是道聽途說,真假難辯,至少目前最新的 Java Web 的架構來說,能搜到較多的是 Spring MVC ,足以說明問題了。
這個請求與方法的映射的注解寫法,俺還得繼續深入研究、測試後,再補足說明。
俺的簡簡單單地就能進這個方法的斷點了,而俺還配了一些 Mybatis 的依賴注入在 Spring 的配置檔案中,實際運作時,确死活也沒有接口對應的實作被注入。
重新研究 Spring 的依賴注入,才發現,和 N 年前的了解相去甚遠,N 年前,把它想得太偉大了,以前是動态偵測類的調用,然後去執行個體化對象,現在明白了,Srping 上下文對象裡有個 控制反轉容器,用于存儲從配置檔案中執行個體化的這些 bean 并把它們裝配起來,所謂的裝配,就是誰是誰的屬性,那就放到那個屬性裡去。
這樣來看,Spring 執行個體化的這些類形成了一個大串串,如果沒有 Spring 所掌管的容器,這些頂層的類執行個體就沒有人引用它了,結果自然是釋放了,頂級實放,其屬性消失,屬性索引的類執行個體也就釋放了,一級一級的下去。這當然是不可能的,因為 Spring 确實索引了這些類執行個體,并放到了 Web 應用上下文中,以便能被通路到。
确實有想過,在控制器類中去這樣取,但這種套路,未免小看 Spring 了吧,基于這個想法,Spring MVC 根據請求搜尋控制器類的時侯,按注解找到了能響應這個請求的類之後,該怎麼做呢?
一種,執行個體化它,另一種從 Spring MVC 索引的類中取到對應的執行個體,但确實不知道 web.xml 中配置的Srping MVC 和 Spring 兩者如何關聯起來,而實際是否使用了,也不得而知。
這裡想到一個好辦法,在 Spring 的配置中,對控制器類加個屬性,并設一個字元串值,在控制器類中,真實地加個字元串類型的屬性,這樣再斷點調試,進入到控制器後,發現這個新加的屬性的值并不是在 Spring配置中設定的值,這一點說明,Spring MVC 确實沒有使用 Spring 索引的那些個類,說明二者并不互相知道對方的存在。
經網查,确實有人也提出,Spring 和Spring MVC 一起配的這種方式,不可用。
那麼 Srping MVC 不會弱智到這種程度,沒辦法和 Spring 整合吧,這一家的東西出現這種情況,那不被人家笑掉大牙才怪,那不成了禍裡搞了嗎!
此時需要正能量,正能量面前,人們總會以積極的方式來思考問題,那就是,這兩個東西要麼互相能接口,要麼 Spring MVC 本身就已經基于 Spring 在做事情,那它内部自然會實作了 Spring 的機制。
不妨試試,把 Spring 的配置檔案,同時配給 Spring MVC ,而且網查結果,兩者用的是同一個名稱的參數名: contextConfigLocation ,有點意思,應該可行。
意思就是讓 SpringMVC 即負責 MVC 請求分發,又管理類的依賴注入,開動,調試。
進入控制器類,檢視運作時新加字元串屬性的值,啊哈哈,已經是 Spring 配置檔案中設定的屬性值了。
由此可見,Spring MVC 内部不光能處理 MVC 的請求分發,同時也維護着 Spring 的依賴注入,即配置檔案中類的執行個體化與裝配,當一個請求交給 Spring MVC 分發器時,它先去指定路徑搜尋類中的注解,及方法注解,找到能比對該請求的類及方法後,從其維護的 Spring 依賴注入類樹中找到該類,并調用該類的對應方法。
至此,問題解決了。
還有一個問題,就是 Mybatis 的映射的依賴注入,如下官方文檔中的 Java 代碼,如何在 Spring 中配置,稍侯研究,再行發文:
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}
----------補充----------
上面的問題,終于找到答案了,原來,這個需要用到 MyBatis-Spring ,它會通過配置于 Spring 中來注入可用的執行個體;
下面是一種針對一組映射器生成注入執行個體的方式,由 MapperScannerConfigurer 負責生成多個 MapperFactoryBean,可以直接拿來注入到其它地方的對應接口上,當然了,确實接口聲明同包路徑下有同名的 .xml 映射器檔案是前提,要不然就得另外指定映射器配置檔案位置了,約定重于配置,盡量還是别配置了,就按約定的來吧,簡單且有條理。
(這裡需要補充說明一下,雖然看似注入的 MapperFactoryBean ,而我确說是映射器的實作,這裡有個饒頭,那就是 MapperFactoryBean 是一個工廠 bean,工廠 bean 在 Spring 注入中有特殊的用途,注入時會調用工廠類的 getObject() 方法,将獲得的對象進入注入,這就是解釋了,工廠類不執行個體化,确要注入,另注入工廠類确得到映射器接口的實作類的原因。這個可以參考一下這篇文章)
以上問題糾結,源于最新的一份官方文檔,其中并未明确提及依賴注入,而一篇老文檔中有說到,這個透露着什麼樣的資訊呢?不得而知,也或許這份最新的文檔,還沒完善呢吧。。。
Mybatis 最新文檔?
Mybatis 老文檔
噢,原來這一篇是 MyBatis-Spring 的文檔,原來兩者是有不同的。。。啊!
由此可見,知道的多而不會用,總比啥都不知道要強,真要找資料,也能門兒清,這就是解決問題的思路吧!
平時扯蛋時,其實扯的就是思路,平時多扯點兒這方面兒的蛋,真正研究時,也就不那麼難了。