Spring是一個開源框架,主要實現兩件事,IOC(控制反轉)和AOP(面向切面編程)。
IOC
控制反轉,也可以稱為依賴倒置。
所謂依賴,從程序的角度看,就是比如A要調用B的方法,那麼A就依賴於B,反正A要用到B,則A依賴於B。所謂倒置,你必須理解如果不倒置,會怎麼著,因為A必須要有B,才可以調用B,如果不倒置,意思就是A主動獲取B的實例:Bb=newB(),這就是最簡單的獲取B實例的方法(當然還有各種設計模式可以幫助你去獲得B的實例,比如工廠、Locator等等),然後你就可以調用b對象了。所以,不倒置,意味著A要主動獲取B,才能使用B;到了這裡,就應該明白了倒置的意思了。倒置就是A要調用B的話,A並不需要主動獲取B,而是由其它人自動將B送上門來。
所謂控制反轉,就是控制權的轉移,舉例說明:一個人要開車,正常情況下,人應該自己去找車,而實現控制反轉後,人就不需要考慮車從哪裡來了,直接開就行了,人就把找車的控制權轉移給了別的對象。體會一下下面的代碼
先定義一個接口Car
public interface Car { void go();}定義兩種車
public class Benz implements Car { public void go() { System.out.println("benz go......"); }}public class BMW implements Car{ public void go() { System.out.println("bmw go......"); }}下面是人開車
public class Person { Car car=new Benz(); void DriveCar(){ System.out.println("begin drive"); car.go(); }}這是正常的代碼控制流程,人想要開車,就要自己去實例化一輛車。但是,這樣子的話,這個人就只能開一種車。怎麼樣才能讓這個人能開各種車呢,就是要實現控制反轉,也就是說,人不再去自己實例化車了,那人怎樣得到車的對象呢?我們可以通過依賴注入(Dependency Injection,簡稱DI)的方式來讓人得到車的對象,從而實現控制反轉。所以,我們要修改Person類
public class Person { Car car=null; public Person(Car car){ this.car=car; } void driveCar(){ System.out.println("begin drive"); car.go(); }}現在的Person類已經不自己實例化車的對象了,而是通過構造函數來獲得車的對象,所以,這個類就可以開各種車了,只要這個車實現了Car接口就可以。看一下如何使用Person類
public static void main(String[] args) { Person p=new Person(new Benz()); p.driveCar();}現在的Person類可以開不止一種車,只要你通過構造函數傳遞進來。在這個例子中,Car對象就是Person類的依賴,當我們實例化Person類時,將一個Car的實例傳遞給Person類,就是依賴注入,我們的Person類從而實現了控制反轉。
控制反轉到底反轉了什麼?有種說法是這樣的:所謂控制反轉,反轉的是獲取對象依賴的過程。控制權反轉後,獲取依賴對象的過程由自身管理變為由IOC容器注入。
Spring實現依賴注入的方式
在上面的這行代碼中Person p=new Person(new Benz());,我們通過手動的方式new了一個Benz()的對象,然後將其註入到Person類中。而Spring不這麼幹,因為Spring覺得,你這行代碼實例化了一個具體的Benz類,如果你以後想要在這裡實例化一個BMW類的話,豈不是要修改代碼?那我乾脆寫到配置文件裡好了,即便你將來要該注意,至少不需要修改代碼,於是就有了下面的配置
<beans> <bean id="car" /> <bean id="person" > <property name="car" ref="car" /> <bean/></beans>
然後,Spring再提供一些機制,從配置文件中獲取Person類的對象時,它所以來的car對象會被裝配進來,而person對像不需要關心到底是哪個具體的類被傳遞進來了。所以,Spring作為一個IOC框架主要做了兩步:創建對象和組裝對象之間的關係。
AOP
AOP(Aspect Oriented Programming)是面向切面編程,下面我來舉例說明什麼是切面。在一個完整的網站項目中,很多模塊都需要做日誌記錄,很多地方都需要做登錄判斷,很多地方都需要做異常處理。日誌記錄,登錄判斷,異常處理等這些邏輯,就是所謂的切面。假設我將這些切面的邏輯寫得到處都是,那麼代碼的可維護性就可想而知了。 AOP就是為了實現關注點分離,將這些切面的邏輯抽出來寫到單獨的類中,然後再想辦法將他們與一般的模塊組裝到一塊來執行,普通模塊甚至都不知道他們已經和切面組裝到一塊了。
面向切面編程的目標就是分離關注點。什麼是關注點呢?就是你要做的事,就是關注點。假如你是個公子哥,沒啥人生目標,天天就是衣來伸手,飯來張口,整天只知道玩一件事!那麼,每天你一睜眼,就光想著吃完飯就去玩(你必須要做的事),但是在玩之前,你還需要穿衣服、穿鞋子、疊好被子、做飯等等等等事情,這些事情就是你的關注點,但是你只想吃飯然後玩,那麼怎麼辦呢?這些事情通通交給別人去幹。在你走到飯桌之前,有一個專門的僕人A幫你穿衣服,僕人B幫你穿鞋子,僕人C幫你疊好被子,僕人C幫你做飯,然後你就開始吃飯、去玩(這就是你一天的正事),你幹完你的正事之後,回來,然後一系列僕人又開始幫你幹這個乾那個,然後一天就結束了!
AOP的好處就是你只需要幹你的正事,其它事情別人幫你幹。也許有一天,你想裸奔,不想穿衣服,那麼你把僕人A解僱就是了!也許有一天,出門之前你還想帶點錢,那麼你再僱一個僕人D專門幫你幹取錢的活!這就是AOP。每個人各司其職,靈活組合,達到一種可配置的、可插拔的程序結構。
從Spring的角度看,AOP最大的用途就在於提供了事務管理的能力。事務管理就是一個關注點,你的正事就是去訪問數據庫,而你不想管事務(太煩),所以,Spring在你訪問數據庫之前,自動幫你開啟事務,當你訪問數據庫結束之後,自動幫你提交/回滾事務!
看下面的代碼,看不懂沒關係
<bean id="audience" /><aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression= "execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:before pointcut-ref="performance" method="takeSeats" /> <!--<co id="co_refPointcut"/>--> <aop:before pointcut-ref="performance" method="turnOffCellPhones" /> <!--<co id="co_refPointcut"/>--> <aop:after-returning pointcut-ref="performance" method="applaud" /> <!--<co id="co_refPointcut"/>--> <aop:after-throwing pointcut-ref="performance" method="demandRefund" /> <!--<co id="co_refPointcut"/>--> </aop:aspect></aop:config>
上面配置的大概意思是,當Performer.perform方法將要發生時,Spring框架中的代理會將目標方法(Performer.perform())攔截下來,執行目標方法前先執行Audience.takeSeats()和Audienceturn.OffCellPhones()方法,然後運行目標方法,當目標方法執行完畢返回時,再運行Audienceturn.applaud()方法。如果目標方法不幸拋出了異常,代理會運行Audienceturn.demandRefund()方法。總之,Spring的代理類全方位地監控了目標方法的執行,而目標方法只專注於自己的事情,甚至都不知道代理類的存在。
總結
以上就是本文關於簡單理解Spring之IOC和AOP及代碼示例的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站:
Spring的Ioc模擬實現詳細介紹
Spring AOP攔截-三種方式實現自動代理詳解
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!