一、實(shí)例化Bean的三種方式
1.構(gòu)造器實(shí)例化
2.靜態(tài)工廠方式實(shí)例化
3.實(shí)例工廠方式實(shí)例化
二、為什么用aop
1、就是為了方便,看一個(gè)國外很有名的大師說,編程的人都是“懶人”,因?yàn)樗炎约鹤龅氖虑槎甲尦绦蜃隽?。用了aop能讓你少寫很多代碼,這點(diǎn)就夠充分了吧
2、就是為了更清晰的邏輯,可以讓你的業(yè)務(wù)邏輯去關(guān)注自己本身的業(yè)務(wù),而不去想一些其他的事情,這些其他的事情包括:安全,事物,日志等。
3.那些aop的術(shù)語
- 通知(Advice)
就是你想要的功能,也就是上面說的 安全,事物,日志等。你給先定義好把,然后在想用的地方用一下。 - 連接點(diǎn)(JoinPoint)
這個(gè)更好解釋了,就是spring允許你使用通知的地方,那可真就多了,基本每個(gè)方法的前,后(兩者都有也行),或拋出異常時(shí)都可以是連接點(diǎn),spring只支持方法連接點(diǎn).其他如aspectJ還可以讓你在構(gòu)造器或?qū)傩宰⑷霑r(shí)都行,不過那不是咱關(guān)注的,只要記住,和方法有關(guān)的前前后后(拋出異常),都是連接點(diǎn)。 - 切入點(diǎn)(Pointcut)
上面說的連接點(diǎn)的基礎(chǔ)上,來定義切入點(diǎn),你的一個(gè)類里,有15個(gè)方法,那就有幾十個(gè)連接點(diǎn)了對把,但是你并不想在所有方法附近都使用通知(使用叫織入,以后再說),你只想讓其中的幾個(gè),在調(diào)用這幾個(gè)方法之前,之后或者拋出異常時(shí)干點(diǎn)什么,那么就用切點(diǎn)來定義這幾個(gè)方法,讓切點(diǎn)來篩選連接點(diǎn),選中那幾個(gè)你想要的方法。 - 切面(Aspect)
切面是通知和切入點(diǎn)的結(jié)合?,F(xiàn)在發(fā)現(xiàn)了吧,沒連接點(diǎn)什么事情,連接點(diǎn)就是為了讓你好理解切點(diǎn),搞出來的,明白這個(gè)概念就行了。通知說明了干什么和什么時(shí)候干(什么時(shí)候通過方法名中的before,after,around等就能知道),而切入點(diǎn)說明了在哪干(指定到底是哪個(gè)方法),這就是一個(gè)完整的切面定義。 - 引入(introduction)
允許我們向現(xiàn)有的類添加新方法屬性。這不就是把切面(也就是新方法屬性:通知定義的)用到目標(biāo)類中嗎 - 目標(biāo)(target)
引入中所提到的目標(biāo)類,也就是要被通知的對象,也就是真正的業(yè)務(wù)邏輯,他可以在毫不知情的情況下,被咱們織入切面。而自己專注于業(yè)務(wù)本身的邏輯。 - 代理(proxy)
怎么實(shí)現(xiàn)整套aop機(jī)制的,都是通過代理,這個(gè)一會給細(xì)說。 - 織入(weaving)
把切面應(yīng)用到目標(biāo)對象來創(chuàng)建新的代理對象的過程。有3種方式,spring采用的是運(yùn)行時(shí),為什么是運(yùn)行時(shí),后面解釋。
關(guān)鍵就是:切點(diǎn)定義了哪些連接點(diǎn)會得到通知
三、理解的AOP原理
spring用代理類包裹切面,把他們織入到Spring管理的bean中。也就是說代理類偽裝成目標(biāo)類,它會截取對目標(biāo)類中方法的調(diào)用,讓調(diào)用者對目標(biāo)類的調(diào)用都先變成調(diào)用偽裝類,偽裝類中就先執(zhí)行了切面,再把調(diào)用轉(zhuǎn)發(fā)給真正的目標(biāo)bean。
現(xiàn)在可以自己想一想,怎么搞出來這個(gè)偽裝類,才不會被調(diào)用者發(fā)現(xiàn)(過JVM的檢查,JAVA是強(qiáng)類型檢查,哪里都要檢查類型)。
1.實(shí)現(xiàn)和目標(biāo)類相同的接口,我也實(shí)現(xiàn)和你一樣的接口,反正上層都是接口級別的調(diào)用,這樣我就偽裝成了和目標(biāo)類一樣的類(實(shí)現(xiàn)了同一接口,咱是兄弟了),也就逃過了類型檢查,到j(luò)ava運(yùn)行期的時(shí)候,利用多態(tài)的后期綁定(所以spring采用運(yùn)行時(shí)),偽裝類(代理類)就變成了接口的真正實(shí)現(xiàn),而他里面包裹了真實(shí)的那個(gè)目標(biāo)類,最后實(shí)現(xiàn)具體功能的還是目標(biāo)類,只不過偽裝類在之前干了點(diǎn)事情(寫日志,安全檢查,事物等)。
這就好比,一個(gè)人讓你辦件事,每次這個(gè)時(shí)候,你弟弟就會先出來,當(dāng)然他分不出來了,以為是你,你這個(gè)弟弟雖然辦不了這事,但是他知道你能辦,所以就答應(yīng)下來了,并且收了點(diǎn)禮物(寫日志),收完禮物了,給把事給人家辦了啊,所以你弟弟又找你這個(gè)哥哥來了,最后把這是辦了的還是你自己。但是你自己并不知道你弟弟已經(jīng)收禮物了,你只是專心把這件事情做好。
順著這個(gè)思路想,要是本身這個(gè)類就沒實(shí)現(xiàn)一個(gè)接口呢,你怎么偽裝我,我就壓根沒有機(jī)會讓你搞出這個(gè)雙胞胎的弟弟,那么就用第2種代理方式,創(chuàng)建一個(gè)目標(biāo)類的子類,生個(gè)兒子,讓兒子偽裝我
2.生成子類調(diào)用,這次用子類來做為偽裝類,當(dāng)然這樣也能逃過JVM的強(qiáng)類型檢查,我繼承的嗎,當(dāng)然查不出來了,子類重寫了目標(biāo)類的所有方法,當(dāng)然在這些重寫的方法中,不僅實(shí)現(xiàn)了目標(biāo)類的功能,還在這些功能之前,實(shí)現(xiàn)了一些其他的(寫日志,安全檢查,事物等)。
這次的對比就是,兒子先從爸爸那把本事都學(xué)會了,所有人都找兒子辦事情,但是兒子每次辦和爸爸同樣的事之前,都要收點(diǎn)小禮物(寫日志),然后才去辦真正的事。當(dāng)然爸爸是不知道兒子這么干的了。這里就有件事情要說,某些本事是爸爸獨(dú)有的(final的),兒子學(xué)不了,學(xué)不了就辦不了這件事,辦不了這個(gè)事情,自然就不能收人家禮了。
前一種兄弟模式,spring會使用JDK的java.lang.reflect.Proxy類,它允許Spring動態(tài)生成一個(gè)新類來實(shí)現(xiàn)必要的接口,織入通知,并且把對這些接口的任何調(diào)用都轉(zhuǎn)發(fā)到目標(biāo)類。
后一種父子模式,spring使用CGLIB庫生成目標(biāo)類的一個(gè)子類,在創(chuàng)建這個(gè)子類的時(shí)候,spring織入通知,并且把對這個(gè)子類的調(diào)用委托到目標(biāo)類。
相比之下,還是兄弟模式好些,他能更好的實(shí)現(xiàn)松耦合,尤其在今天都高喊著面向接口編程的情況下,父子模式只是在沒有實(shí)現(xiàn)接口的時(shí)候,也能織入通知,應(yīng)當(dāng)做一種例外。
四、spring AOP與AspectJ
- 框架:如果應(yīng)用程序不使用Spring框架,那么我們別無選擇,只能放棄使用Spring AOP的想法,因?yàn)樗鼰o法管理任何超出spring容器范圍的東西。 但是,如果我們的應(yīng)用程序完全是使用Spring框架創(chuàng)建的,那么我們可以使用Spring AOP,因?yàn)樗苤苯颖阌趯W(xué)習(xí)和應(yīng)用。
- 靈活性:鑒于有限的連接點(diǎn)支持,Spring AOP并不是一個(gè)完整的AOP解決方案,但它解決了程序員面臨的最常見的問題。 如果我們想要深入挖掘并利用AOP達(dá)到其最大能力,并希望獲得來自各種可用連接點(diǎn)的支持,那么AspectJ是最佳選擇。
- 性能:如果我們使用有限的切面,那么性能差異很小。 但是,有時(shí)候應(yīng)用程序有數(shù)萬個(gè)切面的情況。 在這種情況下,我們不希望使用運(yùn)行時(shí)織入,所以最好選擇AspectJ。 已知AspectJ比Spring AOP快8到35倍。
- 共同優(yōu)點(diǎn):這兩個(gè)框架是完全兼容的。 我們可以隨時(shí)利用Spring AOP,并且仍然使用AspectJ來獲得前者不支持的連接點(diǎn)。
提示:一分耕耘 一分收獲 加油!
版權(quán)任意