SpringMVC的工作原理圖:
SpringMVC流程 1、 用戶發送請求至前端控制器DispatcherServlet。 2、 DispatcherServlet收到請求調用HandlerMapping處理器映射器。 3、 處理器映射器找到具體的處理器(可以根據xml配置、注解進行查找),生成處理器對象及處理器攔截器(如果有則生成)一並返回給DispatcherServlet。 4、 DispatcherServlet調用HandlerAdapter處理器適配器。 5、 HandlerAdapter經過適配調用具體的處理器(Controller,也叫后端控制器)。 6、 Controller執行完成返回ModelAndView。 7、 HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。 8、 DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。 9、 ViewReslover解析后返回具體View。 10、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。 11、 DispatcherServlet響應用戶。
Spring的IOC原理
控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。IoC 容器:最主要是完成了完成對象的創建和依賴的管理注入等等。
DI,所謂控制反轉,就是把原先我們代碼里面需要實現的對象創建、依賴的代碼,反轉給IOC容器(或Spring框架)來實現。那么必然的我們需要創建一個容器,同時需要一種描述來讓容器知道需要創
建的對象與對象的關系。這個描述最具體表現就是我們可配置的文件。 IOC容器就是具有依賴注入功能的容器,IOC容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。應用程序無
需直接在代碼中new相關的對象,應用程序由IOC容器進行組裝。在Spring中BeanFactory是IOC容器的實際代表者。Spring IOC容器通過讀取配置文件中的配置元數據,通過元數據對應用中的各個對
象進行實例化及裝配。
1. IoC理論的背景
我們都知道,在采用面向對象方法設計的軟件系統中,它的底層實現都是由Ñ個對象組成的,所有的對象通過彼此的合作,最終實現系統的業務邏輯。
如果我們打開機械式手表的后蓋,就會看到與上面類似的情形,各個齒輪分別帶動時針,分針和秒針順時針旋轉,從而在表盤上產生正確的時間。圖1中描述的就是這樣的一個齒輪組,它擁有多個獨立的齒輪,這些齒輪相互嚙合在一起,協同工作,共同完成某項任務。我們可以看到,在這樣的齒輪組中,如果有一個齒輪出了問題,就可能會影響到整個齒輪組的正常運轉。
齒輪組中齒輪之間的嚙合關系,與軟件系統中對象之間的耦合關系非常相似。對象之間的耦合關系是無法避免的,也是必要的,這是協同工作的基礎。現在,伴隨着工業級應用的規模越來越龐大,對象之間的依賴關系也越來越復雜,經常會出現對象之間的多重依賴性關系,因此,架構師和設計師對於系統的分析和設計,將面臨更大的挑戰。對象之間耦合度過高的系統,必然會出現牽一發而動全身的情形。
耦合關系不僅會出現在對象與對象之間,也會出現在軟件系統的各模塊之間,以及軟件系統和硬件系統之間。如何降低系統之間,模塊之間和對象之間的耦合度,是軟件工程永遠追求的目標之一。為了解決對象之間的耦合度過高的問題,軟件專家Michael Mattson提出了IOC理論,用來實現對象之間的“解耦”,目前這個理論已經被成功地應用到實踐當中,很多的J2EE項目均采用了國際奧委會框架產品春季。
2.什么是控制反轉(IoC)
IOC是Inversion of Control的縮寫,多數書籍翻譯成“控制反轉”,還有些書籍翻譯成為“控制反向”或者“控制倒置”。
1996年,Michael Mattson在一篇有關探討面向對象框架的文章中,首先提出了IOC這個概念。對於面向對象設計及編程的基本思想,前面我們已經講了很多了,不再贅述,簡單來說就是把復雜系統分解成相互作用合作的對象,這些對象類通過封裝以后,內部實現對外部是透明的,從而降低了解決問題的復雜度,而且可以靈活地被重用和擴展.IOC理論提出的觀點大體是這樣的:借助於“第三方”實現具有依賴關系的對象之間的,如下圖:
大家看到了吧,由於引進了中間位置的“第三方”,也就是IOC容器,使得A,B,C,d這4個對象沒有了耦合關系,齒輪之間的傳動全部依靠“第三方”了,全部對象的控制權全部上繳給“第三方” IOC容器,所以,IOC容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有對象粘合在一起發揮作用,如果沒有這個“粘合劑”,對象與對象之間會彼此失去聯系,這就是有人把IOC容器比喻成“粘合劑”的由來。
我們再來做個試驗:把上圖中間的IOC容器拿掉,然后再來看看這套系統:
我們現在看到的畫面,就是我們要實現整個系統所需要完成的全部內容。這時候,A,B,C,d這4個對象之間已經沒有了耦合關系,彼此毫無聯系,這樣的話,當你在實現阿的時候,根本無須再去考慮B,C和d了,對象之間的依賴關系已經降低到了最低程度。所以,如果真能實現IOC容器,對於系統開發而言,這將是一件多么美好的事情,參與開發的每一成員只要實現自己的類就可以了,跟別人沒有任何關系!
我們再來看看,控制反轉(IOC)到底為什么要起這么個名字我們來對比一下?
軟件系統在沒有引入IOC容器之前,如圖1所示,對象甲依賴於對象B,那么對象阿在初始化或者運行到某一點的時候,自己必須主動去創建對象乙或者使用已經創建的對象B.無論是創建還是使用對象B,控制權都在自己手上。
軟件系統在引入IOC容器之后,這種情形就完全改變了,如圖3所示,由於IOC容器的加入,對象甲與對象乙之間失去了直接聯系,所以,當對象甲運行到需要對象乙的時候,IOC容器會主動創建一個對象乙注入到對象甲需要的地方。
通過前后的對比,我們不難看出來:對象甲獲得依賴對象乙的過程,由主動行為變為了被動行為,控制權顛倒過來了,這就是“控制反轉”這個名稱的由來。
3. IOC的別名:依賴注入(DI)
2004年,Martin Fowler探討了同一個問題,既然IOC是控制反轉,那么到底是“哪些方面的控制被反轉了呢?”,經過詳細地分析和論證后,他得出了答案:“獲得依賴對象的過程被反轉了”控制被反轉之后,獲得依賴對象的過程由自身管理IOC容器主動注入於是,他給“控制反轉“取了一個更合適的名字叫做”依賴注入(Dependency Injection)“。他的這個答案,實際上給出了實現IOC的方法:注入。所謂依賴注入,就是由IOC容器在運行期間,動態地將某種依賴關系注入到對象之中。
所以,依賴注入(DI)和控制反轉(IOC)是從不同的角度的描述的同一件事情,指就是通過引入IOC容器,利用依賴關系注入的方式,實現對象之間的解耦。
我們舉一個生活中的例子,來幫助理解依賴注入的過程。大家對USB接口和USB設備應該都很熟悉吧,USB為我們使用電腦提供了很大的方便,現在有很多的外部設備都支持USB接口。
現在,我們利用電腦主機和USB接口來實現一個任務:從外部USB設備讀取一個文件。
電腦主機讀取文件的時候,它一點也不會關心USB接口上連接的是什么外部設備,而且它確實也無須知道。它的任務就是讀取USB接口,掛接的外部設備只要符合USB接口標准即可。所以,如果我給電腦主機連接上一個U盤,那么主機就從U盤上讀取文件;如果我給電腦主機連接上一個外置硬盤,那么電腦主機就從外置硬盤上讀取文件。掛接外部設備的權力由我作主,即控制權歸我,至於USB接口掛接的是什么設備,電腦主機是決定不了,它只能被動的接受。電腦主機需要外部設備的時候,根本不用它告訴我,我就會主動幫它掛上它想要的外部設備,你看我的服務是多么的到位。這就是我們生活中常見的一個依賴注入的例子。在這個過程中,我就起到了IOC容器的作用。
通過這個例子,依賴注入的思路已經非常清楚:當電腦主機讀取文件的時候,我就把它所要依賴的外部設備,幫他掛接上。整個外部設備注入的過程和一個被依賴的對象在系統運行時被注入另外一個對象內部的過程完全一樣。
我們把依賴注入應用到軟件系統中,再來描述一下這個過程:
對象A依賴於對象B,當對象 A需要用到對象B的時候,IOC容器就會立即創建一個對象B送給對象A。IOC容器就是一個對象制造工廠,你需要什么,它會給你送去,你直接使用就行了,而再也不用去關心你所用的東西是如何制成的,也不用關心最后是怎么被銷毀的,這一切全部由IOC容器包辦。
在傳統的實現中,由程序內部代碼來控制組件之間的關系。我們經常使用new關鍵字來實現兩個組件之間關系的組合,這種實現方式會造成組件之間耦合。IOC很好地解決了該問題,它將實現組件間關系從程序內部提到外部容器,也就是說由容器在運行期將組件間的某種依賴關系動態注入組件中。
4. IOC為我們帶來了什么好處
我們還是從USB的例子說起,使用USB外部設備比使用內置硬盤,到底帶來什么好處?
第一、USB設備作為電腦主機的外部設備,在插入主機之前,與電腦主機沒有任何的關系,只有被我們連接在一起之后,兩者才發生聯系,具有相關性。所以,無論兩者中的任何一方出現什么的問題,都不會影響另一方的運行。這種特性體現在軟件工程中,就是可維護性比較好,非常便於進行單元測試,便於調試程序和診斷故障。代碼中的每一個Class都可以單獨測試,彼此之間互不影響,只要保證自身的功能無誤即可,這就是組件之間低耦合或者無耦合帶來的好處。
第二、USB設備和電腦主機的之間無關性,還帶來了另外一個好處,生產USB設備的廠商和生產電腦主機的廠商完全可以是互不相干的人,各干各事,他們之間唯一需要遵守的就是USB接口標准。這種特性體現在軟件開發過程中,好處可是太大了。每個開發團隊的成員都只需要關心實現自身的業務邏輯,完全不用去關心其它的人工作進展,因為你的任務跟別人沒有任何關系,你的任務可以單獨測試,你的任務也不用依賴於別人的組件,再也不用扯不清責任了。所以,在一個大中型項目中,團隊成員分工明確、責任明晰,很容易將一個大的任務划分為細小的任務,開發效率和產品質量必將得到大幅度的提高。
第三、同一個USB外部設備可以插接到任何支持USB的設備,可以插接到電腦主機,也可以插接到DV機,USB外部設備可以被反復利用。在軟件工程中,這種特性就是可復用性好,我們可以把具有普遍性的常用組件獨立出來,反復利用到項目中的其它部分,或者是其它項目,當然這也是面向對象的基本特征。顯然,IOC不僅更好地貫徹了這個原則,提高了模塊的可復用性。符合接口標准的實現,都可以插接到支持此標准的模塊中。
第四、同USB外部設備一樣,模塊具有熱插拔特性。IOC生成對象的方式轉為外置方式,也就是把對象生成放在配置文件里進行定義,這樣,當我們更換一個實現子類將會變得很簡單,只要修改配置文件就可以了,完全具有熱插撥的特性。
以上幾點好處,難道還不足以打動我們,讓我們在項目開發過程中使用IOC框架嗎?
5. IOC容器的技術剖析
IOC中最基本的技術就是“反射(Reflection)”編程,目前.Net C#、Java和PHP5等語言均支持,其中PHP5的技術書籍中,有時候也被翻譯成“映射”。有關反射的概念和用法,大家應該都很清楚,通俗來講就是根據給出的類名(字符串方式)來動態地生成對象。這種編程方式可以讓對象在生成時才決定到底是哪一種對象。反射的應用是很廣泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”做為最基本的技術手段。
反射技術其實很早就出現了,但一直被忽略,沒有被進一步的利用。當時的反射編程方式相對於正常的對象生成方式要慢至少得10倍。現在的反射技術經過改良優化,已經非常成熟,反射方式生成對象和通常對象生成方式,速度已經相差不大了,大約為1-2倍的差距。
我們可以把IOC容器的工作模式看做是工廠模式的升華,可以把IOC容器看作是一個工廠,這個工廠里要生產的對象都在配置文件中給出定義,然后利用編程語言的的反射編程,根據配置文件中給出的類名生成相應的對象。從實現來看,IOC是把以前在工廠方法里寫死的對象生成代碼,改變為由配置文件來定義,也就是把工廠和對象生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性。
6. IOC容器的一些產品
Sun ONE技術體系下的IOC容器有:輕量級的有Spring、Guice、Pico Container、Avalon、HiveMind;重量級的有EJB;不輕不重的有JBoss,Jdon等等。Spring框架作為Java開發中SSH(Struts、Spring、Hibernate)三劍客之一,大中小項目中都有使用,非常成熟,應用廣泛,EJB在關鍵性的工業級項目中也被使用,比如某些電信業務。
.Net技術體系下的IOC容器有:Spring.Net、Castle等等。Spring.Net是從Java的Spring移植過來的IOC容器,Castle的IOC容器就是Windsor部分。它們均是輕量級的框架,比較成熟,其中Spring.Net已經被逐漸應用於各種項目中。
7. 使用IOC框架應該注意什么
使用IOC框架產品能夠給我們的開發過程帶來很大的好處,但是也要充分認識引入IOC框架的缺點,做到心中有數,杜絕濫用框架。
第一、軟件系統中由於引入了第三方IOC容器,生成對象的步驟變得有些復雜,本來是兩者之間的事情,又憑空多出一道手續,所以,我們在剛開始使用IOC框架的時候,會感覺系統變得不太直觀。所以,引入了一個全新的框架,就會增加團隊成員學習和認識的培訓成本,並且在以后的運行維護中,還得讓新加入者具備同樣的知識體系。
第二、由於IOC容器生成對象是通過反射方式,在運行效率上有一定的損耗。如果你要追求運行效率的話,就必須對此進行權衡。
第三、具體到IOC框架產品(比如:Spring)來講,需要進行大量的配制工作,比較繁瑣,對於一些小的項目而言,客觀上也可能加大一些工作成本。
第四、IOC框架產品本身的成熟度需要進行評估,如果引入一個不成熟的IOC框架產品,那么會影響到整個項目,所以這也是一個隱性的風險。
我們大體可以得出這樣的結論:一些工作量不大的項目或者產品,不太適合使用IOC框架產品。另外,如果團隊成員的知識能力欠缺,對於IOC框架產品缺乏深入的理解,也不要貿然引入。最后,特別強調運行效率的項目或者產品,也不太適合引入IOC框架產品,象WEB2.0網站就是這種情況。
Mybatis工作流程
1.通過SqlSessionFactoryBuilder 解析mybatis-config.xml 文件中的 Configuration 創建一個 sqlSessionFactory 2.通過sqlSessionFactory 創建一個SqlSession 3.SqlSession 調用一個 quary(查詢)Executor執行器,是為了執行sql語句 4. 創建一個新的StatementHandler (參數執行器) 5. 調用ResultSetHandler (結果器返回結果),執行SQl語句,不同的SQl語句返回不同的結果
Spring Aop
- 簡介
前段時間寫的java設計模式--代理模式,最近在看Spring Aop的時候,覺得於代理模式應該有密切的聯系,於是決定了解下Spring Aop的實現原理。
說起AOP就不得不說下OOP了,OOP中引入封裝、繼承和多態性等概念來建立一種對象層次結構,用以模擬公共行為的一個集合。但是,如果我們需要為部分對象引入公共部分的時候,OOP就會引入大量重復的代碼。例如:日志功能。
AOP技術利用一種稱為“橫切”的技術,解剖封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用模塊,這樣就能減少系統的重復代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。AOP把軟件系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關系不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如權限認證、日志、事務處理。
什么是AOP
AOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向對象編程)的補充和完善。例如日志功能。日志代碼往往水平地散布在所有對象層次中,
而與它所散布到的對象的核心功能毫無關系。對於其他類型的代碼,如安全性、異常處理和透明的持續性也是如此。這種散布在各處的無關的代碼被稱為橫切(cross-cutting)代碼,在OOP設計中,它導致了
大量代碼的重復,而不利於各個模塊的重用。AOP技術它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用模塊,並將其名為“Aspect”,即方面。所謂“方面”
,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重復代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。使用“橫切”技術,AOP把軟件系統分為
兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關系不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如權限認證、日志、
事務處理。Aop 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。正如Avanade公司的高級方案構架師Adam Magee所說,AOP的核心思想就是“將應用程序中的商業邏輯同對其提供支持的
通用服務進行分離。”實現AOP的技術,主要分為兩大類:一是采用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行為的執行;二是采用靜態織入的方式,引入特定的語法創建“方面”,從而
使得編譯器可以在編譯期間織入有關“方面”的代碼。
AOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向對象編程)的補充和完善。OOP引入封裝、繼承和多態性等概念來建立一種對象層次結構,用以模擬公共行為的一個集合。當我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關系,但並不適合定義從左到右的關系。例如日志功能。日志代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關系。對於其他類型的代碼,如安全性、異常處理和透明的持續性也是如此。這種散布在各處的無關的代碼被稱為橫切(cross-cutting)代碼,在OOP設計中,它導致了大量代碼的重復,而不利於各個模塊的重用。
而AOP技術則恰恰相反,它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用模塊,並將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重復代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。AOP代表的是一個橫向的關系,如果說“對象”是一個空心的圓柱體,其中封裝的是對象的屬性和行為;那么面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開,以獲得其內部的消息。而剖開的切面,也就是所謂的“方面”了。然后它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。
使用“橫切”技術,AOP把軟件系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關系不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如權限認證、日志、事務處理。Aop 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。正如Avanade公司的高級方案構架師Adam Magee所說,AOP的核心思想就是“將應用程序中的商業邏輯同對其提供支持的通用服務進行分離。”
實現AOP的技術,主要分為兩大類:一是采用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行為的執行;二是采用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的代碼。
AOP使用場景
AOP用來封裝橫切關注點,具體可以在下面的場景中使用:
Authentication 權限
Caching 緩存
Context passing 內容傳遞
Error handling 錯誤處理
Lazy loading 懶加載
Debugging 調試
logging, tracing, profiling and monitoring 記錄跟蹤 優化 校准
Performance optimization 性能優化
Persistence 持久化
Resource pooling 資源池
Synchronization 同步
Transactions 事務
AOP相關概念
方面(Aspect):一個關注點的模塊化,這個關注點實現可能另外橫切多個對象。事務管理是J2EE應用中一個很好的橫切關注點例子。方面用Spring的 Advisor或攔截器實現。
連接點(Joinpoint): 程序執行過程中明確的點,如方法的調用或特定的異常被拋出。
通知(Advice): 在特定的連接點,AOP框架執行的動作。各種類型的通知包括“around”、“before”和“throws”通知。通知類型將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連接點的攔截器鏈。Spring中定義了四個advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice
切入點(Pointcut): 指定一個通知將被引發的一系列連接點的集合。AOP框架必須允許開發者指定切入點:例如,使用正則表達式。 Spring定義了Pointcut接口,用來組合MethodMatcher和ClassFilter,可以通過名字很清楚的理解, MethodMatcher是用來檢查目標類的方法是否可以被應用此通知,而ClassFilter是用來檢查Pointcut是否應該應用到目標類上
引入(Introduction): 添加方法或字段到被通知的類。 Spring允許引入新的接口到任何被通知的對象。例如,你可以使用一個引入使任何對象實現 IsModified接口,來簡化緩存。Spring中要使用Introduction, 可有通過DelegatingIntroductionInterceptor來實現通知,通過DefaultIntroductionAdvisor來配置Advice和代理類要實現的接口
目標對象(Target Object): 包含連接點的對象。也被稱作被通知或被代理對象。POJO
AOP代理(AOP Proxy): AOP框架創建的對象,包含通知。 在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。
織入(Weaving): 組裝方面來創建一個被通知對象。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在運行時完成。Spring和其他純Java AOP框架一樣,在運行時完成織入。
如何使用Spring AOP
可以通過配置文件或者編程的方式來使用Spring AOP。
配置可以通過xml文件來進行,大概有四種方式:
1. 配置ProxyFactoryBean,顯式地設置advisors, advice, target等
2. 配置AutoProxyCreator,這種方式下,還是如以前一樣使用定義的bean,但是從容器中獲得的其實已經是代理對象
3. 通過<aop:config>來配置
4. 通過<aop: aspectj-autoproxy>來配置,使用AspectJ的注解來標識通知及切入點
也可以直接使用ProxyFactory來以編程的方式使用Spring AOP,通過ProxyFactory提供的方法可以設置target對象, advisor等相關配置,最終通過 getProxy()方法來獲取代理對象