簡單理解Spring之IOC和AOP及代碼示例
Spring是一個開源框架,主要實現(xiàn)兩件事,IOC(控制反轉(zhuǎn))和AOP(面向切面編程)。
IOC
控制反轉(zhuǎn),也可以稱為依賴倒置。
所謂依賴,從程序的角度看,就是比如A要調(diào)用B的方法,那么A就依賴于B,反正A要用到B,則A依賴于B。所謂倒置,你必須理解如果不倒置,會怎么著,因為A必須要有B,才可以調(diào)用B,如果不倒置,意思就是A主動獲取B的實例:Bb=newB(),這就是最簡單的獲取B實例的方法(當(dāng)然還有各種設(shè)計模式可以幫助你去獲得B的實例,比如工廠、Locator等等),然后你就可以調(diào)用b對象了。所以,不倒置,意味著A要主動獲取B,才能使用B;到了這里,就應(yīng)該明白了倒置的意思了。倒置就是A要調(diào)用B的話,A并不需要主動獲取B,而是由其它人自動將B送上門來。
所謂控制反轉(zhuǎn),就是控制權(quán)的轉(zhuǎn)移,舉例說明:一個人要開車,正常情況下,人應(yīng)該自己去找車,而實現(xiàn)控制反轉(zhuǎn)后,人就不需要考慮車從哪里來了,直接開就行了,人就把找車的控制權(quán)轉(zhuǎn)移給了別的對象。體會一下下面的代碼
先定義一個接口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();
}
}
這是正常的代碼控制流程,人想要開車,就要自己去實例化一輛車。但是,這樣子的話,這個人就只能開一種車。怎么樣才能讓這個人能開各種車呢,就是要實現(xiàn)控制反轉(zhuǎn),也就是說,人不再去自己實例化車了,那人怎樣得到車的對象呢?我們可以通過依賴注入(Dependency Injection,簡稱DI)的方式來讓人得到車的對象,從而實現(xiàn)控制反轉(zhuǎn)。所以,我們要修改Person類
public class Person {
Car car=null;
public Person(Car car){
this.car=car;
}
void driveCar(){
System.out.println("begin drive");
car.go();
}
}
現(xiàn)在的Person類已經(jīng)不自己實例化車的對象了,而是通過構(gòu)造函數(shù)來獲得車的對象,所以,這個類就可以開各種車了,只要這個車實現(xiàn)了Car接口就可以??匆幌氯绾问褂肞erson類
public static void main(String[] args) {
Person p=new Person(new Benz());
p.driveCar();
}
現(xiàn)在的Person類可以開不止一種車,只要你通過構(gòu)造函數(shù)傳遞進(jìn)來。在這個例子中,Car對象就是Person類的依賴,當(dāng)我們實例化Person類時,將一個Car的實例傳遞給Person類,就是依賴注入,我們的Person類從而實現(xiàn)了控制反轉(zhuǎn)。
控制反轉(zhuǎn)到底反轉(zhuǎn)了什么?有種說法是這樣的:所謂控制反轉(zhuǎn),反轉(zhuǎn)的是獲取對象依賴的過程??刂茩?quán)反轉(zhuǎn)后,獲取依賴對象的過程由自身管理變?yōu)橛蒊OC容器注入。
Spring實現(xiàn)依賴注入的方式
在上面的這行代碼中Person p=new Person(new Benz());,我們通過手動的方式new了一個Benz()的對象,然后將其注入到Person類中。而Spring不這么干,因為Spring覺得,你這行代碼實例化了一個具體的Benz類,如果你以后想要在這里實例化一個BMW類的話,豈不是要修改代碼?那我干脆寫到配置文件里好了,即便你將來要該注意,至少不需要修改代碼,于是就有了下面的配置
<beans>
<bean id="car" class="com.XXX.Benz" />
<bean id="person" class="com.XXX.Person" >
<property name="car" ref="car" />
<bean/>
</beans>
然后,Spring再提供一些機(jī)制,從配置文件中獲取Person類的對象時,它所以來的car對象會被裝配進(jìn)來,而person對象不需要關(guān)心到底是哪個具體的類被傳遞進(jìn)來了。所以,Spring作為一個IOC框架主要做了兩步:創(chuàng)建對象和組裝對象之間的關(guān)系。
AOP
AOP(Aspect Oriented Programming)是面向切面編程,下面我來舉例說明什么是切面。在一個完整的網(wǎng)站項目中,很多模塊都需要做日志記錄,很多地方都需要做登錄判斷,很多地方都需要做異常處理。日志記錄,登錄判斷,異常處理等這些邏輯,就是所謂的切面。假設(shè)我將這些切面的邏輯寫得到處都是,那么代碼的可維護(hù)性就可想而知了。AOP就是為了實現(xiàn)關(guān)注點(diǎn)分離,將這些切面的邏輯抽出來寫到單獨(dú)的類中,然后再想辦法將他們與一般的模塊組裝到一塊來執(zhí)行,普通模塊甚至都不知道他們已經(jīng)和切面組裝到一塊了。
面向切面編程的目標(biāo)就是分離關(guān)注點(diǎn)。什么是關(guān)注點(diǎn)呢?就是你要做的事,就是關(guān)注點(diǎn)。假如你是個公子哥,沒啥人生目標(biāo),天天就是衣來伸手,飯來張口,整天只知道玩一件事!那么,每天你一睜眼,就光想著吃完飯就去玩(你必須要做的事),但是在玩之前,你還需要穿衣服、穿鞋子、疊好被子、做飯等等等等事情,這些事情就是你的關(guān)注點(diǎn),但是你只想吃飯然后玩,那么怎么辦呢?這些事情通通交給別人去干。在你走到飯桌之前,有一個專門的仆人A幫你穿衣服,仆人B幫你穿鞋子,仆人C幫你疊好被子,仆人C幫你做飯,然后你就開始吃飯、去玩(這就是你一天的正事),你干完你的正事之后,回來,然后一系列仆人又開始幫你干這個干那個,然后一天就結(jié)束了!
AOP的好處就是你只需要干你的正事,其它事情別人幫你干。也許有一天,你想裸奔,不想穿衣服,那么你把仆人A解雇就是了!也許有一天,出門之前你還想帶點(diǎn)錢,那么你再雇一個仆人D專門幫你干取錢的活!這就是AOP。每個人各司其職,靈活組合,達(dá)到一種可配置的、可插拔的程序結(jié)構(gòu)。
從Spring的角度看,AOP最大的用途就在于提供了事務(wù)管理的能力。事務(wù)管理就是一個關(guān)注點(diǎn),你的正事就是去訪問數(shù)據(jù)庫,而你不想管事務(wù)(太煩),所以,Spring在你訪問數(shù)據(jù)庫之前,自動幫你開啟事務(wù),當(dāng)你訪問數(shù)據(jù)庫結(jié)束之后,自動幫你提交/回滾事務(wù)!
看下面的代碼,看不懂沒關(guān)系
<bean id="audience" class="com.springinaction.springidol.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>
上面配置的大概意思是,當(dāng)Performer.perform方法將要發(fā)生時,Spring框架中的代理會將目標(biāo)方法(Performer.perform())攔截下來,執(zhí)行目標(biāo)方法前先執(zhí)行Audience.takeSeats()和Audienceturn.OffCellPhones()方法,然后運(yùn)行目標(biāo)方法,當(dāng)目標(biāo)方法執(zhí)行完畢返回時,再運(yùn)行Audienceturn.applaud()方法。如果目標(biāo)方法不幸拋出了異常,代理會運(yùn)行Audienceturn.demandRefund()方法。總之,Spring的代理類全方位地監(jiān)控了目標(biāo)方法的執(zhí)行,而目標(biāo)方法只專注于自己的事情,甚至都不知道代理類的存在。
總結(jié)
以上就是本文關(guān)于簡單理解Spring之IOC和AOP及代碼示例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
Spring AOP攔截-三種方式實現(xiàn)自動代理詳解
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
剖析Java中HashMap數(shù)據(jù)結(jié)構(gòu)的源碼及其性能優(yōu)化
這篇文章主要介紹了Java中HashMap數(shù)據(jù)結(jié)構(gòu)的源碼及其性能優(yōu)化,文中以Java 8后HashMap的性能提升來討論了HashMap的一些優(yōu)化點(diǎn),需要的朋友可以參考下2016-05-05
SpringBoot+vue+Axios實現(xiàn)Token令牌的詳細(xì)過程
Token是在服務(wù)端產(chǎn)生的,前端可以使用用戶名/密碼向服務(wù)端請求認(rèn)證(登錄),服務(wù)端認(rèn)證成功,服務(wù)端會返回?Token?給前端,Token可以使用自己的算法自定義,本文給大家介紹SpringBoot+vue+Axios實現(xiàn)Token令牌,感興趣的朋友一起看看吧2023-10-10
SpringBoot基于Sentinel在服務(wù)上實現(xiàn)接口限流
這篇文章主要介紹了SpringBoot基于Sentinel在服務(wù)上實現(xiàn)接口限流,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
java開發(fā)ExecutorService監(jiān)控實現(xiàn)示例詳解
這篇文章主要為大家介紹了java開發(fā)ExecutorService監(jiān)控實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

