Spring入門IOC和AOP學習筆記
1. 概述
Spring框架的核心有兩個:
Spring容器作為超級大工廠乔询,負責管理蔼啦、創(chuàng)建所有的Java對象缸剪,這些Java對象被稱為Bean躺率。
Spring容器管理容器中Bean之間的依賴關(guān)系,使用一種叫做“依賴注入”的方式來管理bean之間的依賴關(guān)系照皆。
Spring有兩個核心接口:BeanFactory
和ApplicationContext
,ApplicationContext
是BeanFactory
的子接口、它們都可以代表Spring容器鸠信,Spring容器是生成Bean實例的工廠纵寝,并管理容器中的Bean。建議優(yōu)先使用ApplicationContext。除非對內(nèi)存非常關(guān)鍵的應(yīng)用再考慮使用BeanFactory爽茴。當系統(tǒng)創(chuàng)建ApplicationContext的時候葬凳,默認會預(yù)初始化所有Singleton Bean,這就意味著前期創(chuàng)建ApplicationContext時將有較大的性能開銷室奏,但一旦ApplicationContext初始化完成火焰,程序后面獲取singleton Bean實例時,就擁有較好的性能胧沫。為<bean/>
元素指定lazy-init="true"
那么就不會預(yù)初始化Singleton bean了昌简。
2. IOC
Inversion Of Control,控制反轉(zhuǎn)绒怨,也可以叫依賴注入纯赎。A對象需要調(diào)用B對象的方法的情景,這種情形稱為依賴南蹂,即A對象依賴B對象犬金。使用依賴注入不僅可以為Bean對象注入普通的屬性值,還可以注入其他Bean引用六剥。通過這種依賴注入晚顷,Java EE應(yīng)用中的各種組件不需要以硬編碼方式耦合在一起,甚至無需使用工廠模式疗疟。當某個Java實例需要其他Java實例時该默,系統(tǒng)自動提供所需要的實例,無需程序顯式獲取策彤。
好處
先來說說傳統(tǒng)使用java實例的不足栓袖,一般有兩種方式:
- 通過new關(guān)鍵字實例化一個對象;
- 通過工廠模式生產(chǎn)一個實例對象锅锨;
第一種方式必然導致調(diào)用者和被依賴對象存在硬編碼耦合叽赊,非常不利于項目升級的維護;第二種比第一種好很多必搞,但是調(diào)用組件需要主動通過工廠去獲取被依賴的對象必指,這就會帶來調(diào)用組件與被依賴工廠的耦合。
那么IOC有什么好處呢?
調(diào)用者無需主動獲取被依賴的對象恕洲,只要被動接受Spring容器為調(diào)用者的成員變量即可塔橡。總體來說就是主動變?yōu)楸粍铀冢员环Q為控制反轉(zhuǎn)葛家。
場景
依賴注入一般有以下兩種:
- 設(shè)值注入:IoC容器使用成員變量的setter方法來注入被依賴對象;
- 構(gòu)造注入:IoC容器通過構(gòu)造器來注入被依賴對象泌类;
建議采用設(shè)值注入為主癞谒,構(gòu)造注入為輔的注入策略。對于依賴關(guān)系無需變化的注入,盡量采用構(gòu)造注入弹砚;而其他依賴關(guān)系的注入双仍,則考慮采用設(shè)值注入。
使用IoC容器的三個基本要點:
- 應(yīng)用程序的各組件面向接口編程桌吃,這樣就可以將組件之間的耦合關(guān)系提升到接口層次朱沃,從而有有利于項目后期的發(fā)展;
- 應(yīng)用程序的各組件不再由程序主動創(chuàng)建茅诱,而是由Spring容器來負責產(chǎn)生并初始化逗物;
- Spring采用配置文件或注解來管理Bean的實現(xiàn)類、依賴關(guān)系瑟俭,Spring容器則根據(jù)配置文件或注解翎卓,利用反射來創(chuàng)建實例,并為之注入依賴關(guān)系摆寄。
3. AOP
Aspect Oriented Programming莲祸,面向切面編程,用于在模塊化方面的橫切關(guān)注點椭迎。AOP和OOP(Object Oriented Programming)互為補充,可以這么理解:面向?qū)ο缶幊淌菑撵o態(tài)角度縱向考慮程序結(jié)構(gòu)田盈,面向切面編程則是從動態(tài)角度橫向考慮運行過程畜号。比如一個日記記錄的功能,代碼往往水平的散落在所有對象中允瞧,與被散布的對象的核心功能沒什么關(guān)系简软,這種散布在各個對象中的無關(guān)代碼被稱為“橫切代碼”,在OOP的設(shè)計中述暂,它導致了大量代碼的重復痹升,從而不利于各個模塊的復用。
簡單的說畦韭,它是一個攔截器可以攔截一些過程疼蛾,當一個方法執(zhí)行,Spring AOP可以攔截一個方法的執(zhí)行艺配,在這個方法執(zhí)行的前后添加一些功能察郁。是一個典型代理模式的應(yīng)用。
AOP中的一些術(shù)語
- 切面(Aspect):切面組織多個Advice转唉,Advice放在切面中定義皮钠。
- 連接點(JoinPoint):程序執(zhí)行過程中明確的點,如方法的調(diào)用赠法,或者異常的拋出麦轰,在Spring AOP中,連接點總是方法的調(diào)用。
- 增強處理(Advice):AOP框架在特定的切入點執(zhí)行的增強處理款侵,處理有“before”末荐、“after”、“after-returning”喳坠、“around”鞠评、“after-throwing”等;
- 切入點(Pointcut):可以插增強處理的連接點壕鹉。當某個連接點滿足指定要求時剃幌,該連接點將被添加增強處理(Advice),該連接點也就變成了切入點晾浴。
以一個bean配置為例:
<aop:config>
<!-- order:指定切面bean的優(yōu)先級负乡,值越小,優(yōu)先級越高 -->
<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2">
<aop:around method="processTask" pointcut="execution(* com.wangjun.aop.xml.*.*(..))"/>
<aop:before method="authority" pointcut="execution(* com.wangjun.aop.xml.*.*(..))"/>
<aop:after-returning method="log" returning="rvt" pointcut="execution(* com.wangjun.aop.xml.*.*(..))"/>
</aop:aspect>
</aop:config>
其中<aop:aspect/>
標簽就是切面脊凰,此標簽下面的<aop:around/>
抖棘、<aop:before/>
這些就是增強處理,那么在哪里進行增強處理呢狸涌?pointcut
屬性就定義了切入點切省,也就是在哪里進行增強處理。這里的表達式比如execution(* com.wangjun.aop.xml.*.*(..))
含義如下:
- 指定在com.wangjun.aop.xml包中任意類方法帕胆;
- 第一個*表示返回值不限朝捆,第二個*表示類名不限;
- 第三個*表示方法名不限懒豹,圓括號中的(..)表示任意個數(shù)芙盘、類型不限的形參。
還有一些術(shù)語:
- 引入:將方法或字段添加到被處理的類中脸秽。Spring允許將新的接口引入到任何被處理的對象中儒老,例如,你可以使用一個引入记餐,使任何對象實現(xiàn)isModify接口驮樊,以此來簡化緩存。
- 目標對象:被AOP框架增強處理的對象片酝。如果AOP采用的是動態(tài)AOP實現(xiàn)巩剖,那么該對象就是一個被代理的對象;
- AOP代理:AOP框架創(chuàng)建的對象钠怯,也可以是cglib代理佳魔,代理就是堆目標對象的加強。
- 織入(Weaving):將增強處理添加到目標對象中晦炊,并創(chuàng)建一個被增強的對象的過程就是織入鞠鲜。Spring和其他純javaAOP框架一樣宁脊,在運行時完成織入。
使用場景
日志記錄贤姆、審計榆苞、聲明式事務(wù)、安全性和緩存等霞捡。
AspectJ和Spring AOP的區(qū)別
正好代表了實現(xiàn)AOP的兩種方式:
AspectJ是靜態(tài)實現(xiàn)AOP的坐漏,即在編譯階段對程序進行修改,需要特殊的編譯器碧信,具有較好的性能赊琳;
Spring AOP是動態(tài)實現(xiàn)AOP的,即在運行階段動態(tài)生成AOP代理砰碴,純java實現(xiàn)躏筏,因此無需特殊的編譯器,但是通常性能較差呈枉。
目前Spring已經(jīng)對AspectJ進行了很好的集成趁尼。
Spring實現(xiàn)AOP的方式
- 基于注解的“零配置”方式:使用@Aspect、@Pointcut等注解標注切入點和增強處理猖辫;
- 基于XML配置文件的管理方式:使用Spring配置文件來定義切入點和增強處理酥泞;
Spring AOP的動態(tài)代理
所謂的動態(tài)代理就是說AOP框架不會去修改字節(jié)碼,而是在內(nèi)存中臨時為方法生成一個AOP對象啃憎,這個AOP對象包含了目標對象的全部方法婶博,并且在特定的切點做了增強處理,并回調(diào)原對象的方法荧飞。
Spring AOP中的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理名党。JDK動態(tài)代理通過反射來接收被代理的類叹阔,并且要求被代理的類必須實現(xiàn)一個接口。JDK動態(tài)代理的核心是InvocationHandler
接口和Proxy
類传睹。
如果目標類沒有實現(xiàn)接口耳幢,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標類。CGLIB(Code Generation Library)欧啤,是一個代碼生成的類庫睛藻,可以在運行時動態(tài)的生成某個類的子類,注意邢隧,CGLIB是通過繼承的方式做的動態(tài)代理店印,因此如果某個類被標記為final
,那么它是無法使用CGLIB做動態(tài)代理的倒慧。
4. 學習路徑
- 構(gòu)建AOP和IOC的demo按摘;
- 安裝spring工具套件STS包券;
- 使用無注解方式進行AOP;
- 使用xml配置方式進行AOP炫贤;