Spring學(xué)習(xí)之AOP基礎(chǔ)
前言
最近在學(xué)Spring,這兩天碰到AOP這個概念脐帝,一開始不是很理解其背后的思想同云,經(jīng)過這兩天的學(xué)習(xí),基本上大致理解了其含義以及目的堵腹,故將學(xué)習(xí)過程的筆記整理出來炸站,以供日后回顧使用,以及與各位正在學(xué)習(xí)Spring的朋友分享
AOP的介紹
AOP疚顷,全程是Apsect Orientation Programming旱易,翻譯過來就是面向切面的編程,說到面向切面腿堤,首先需要談到的就是OOP阀坏,也就是比較熟悉的面向?qū)ο缶幊蹋诿嫦驅(qū)ο缶幊讨邪侍矗?dāng)重復(fù)性的代碼出現(xiàn)比較多次的時候忌堂,一般我們就會將公共部分其抽取出來,形成父類酗洒,這樣士修,通過繼承的手段,就能極大地減少代碼的重復(fù)樱衷。然而李命,在實際開發(fā)過程中卻有一些代碼是冗余是,但是通過面向?qū)ο箝_發(fā)的方式卻是無法將其抽取出來箫老,比如說封字,上一篇文章中提到的,日志管理耍鬓,或者常用的事務(wù)管理等阔籽,這些類型的代碼有具有一個很明顯的特點,那就是他們緊緊圍繞在業(yè)務(wù)代碼牲蜀,或者說目標(biāo)代碼的周圍(前/后)笆制,這種形式的代碼采用面向?qū)ο蟮姆绞绞菬o法進行抽取的。于是涣达,需求誕生了解決方案在辆,面向切面的方式就開始投入了使用。
所謂的面向切面編程度苔,其實就是從橫向的角度來處理冗余的代碼(面向?qū)ο蟮木幊谭绞交径际强v向的角度)匆篓,比如說,日志管理寇窑,由于日志管理代碼緊緊圍繞在業(yè)務(wù)代碼中鸦概,從橫向的角度來看這些代碼,日志管理代碼就好像是一層外衣甩骏,緊緊地包圍著業(yè)務(wù)代碼窗市,而面向切面編程的核心思想先慷,就是將這些具有橫向特征的代碼抽取出來,并且將他們集中在特定的類中咨察,然后通過織入的方式论熙,將他們織入到對應(yīng)的業(yè)務(wù)方法中,這樣子摄狱,這些代碼就好像是一層獨立與業(yè)務(wù)代碼的代碼了赴肚,而將他們抽取出來并且在需要的時候?qū)⑺麄冋线M去的方式,就是面向切面編程了二蓝。
這里需要注意一點誉券,面向切面編程的出現(xiàn),不是要替代面向?qū)ο缶幊炭蓿菍ζ溥M行補充踊跟,擴展面向?qū)ο缶幊痰哪芰ΑT谇懊娴囊恍」?jié)鸥诽,動態(tài)代理中也提到了商玫,動態(tài)代理技術(shù)是Spring中AOP應(yīng)用的背景,也就是說牡借,Spring是通過動態(tài)代理技術(shù)來實現(xiàn)面向切面編程的拳昌,有了動態(tài)代理技術(shù)的基礎(chǔ),接下來我們就來學(xué)習(xí)面向切面編程
AOP編程常用術(shù)語
在具體學(xué)習(xí)AOP編程之間钠龙,有幾個比較重要的概念需要弄清楚炬藤,這幾個概念是面向切面編程的基礎(chǔ),也是其核心碴里。
- 連接點 Jointpoint
- 所謂的連接點沈矿,指的是代碼中可以進行增強的點惜犀,比如說方法調(diào)用前绅喉、方法調(diào)用后窃植、方法調(diào)用前后撰茎、類初始化前、類初始化后截碴、異常拋出后
- 切點 Cutpoint
- 切點呀伙,是指要進行增強的點你稚,這里需要注意區(qū)分連接點和切點寇壳,連接點是所有符合條件的點醒颖,而切點是所要進行織入的點,連接點包含了切點九巡,但同時一個切點可能匹配多個連接點
- 增強 Advice
- 增強图贸,指的是所要在切點上執(zhí)行的代碼蹂季,也就是具體的想要增強的代碼冕广,一般還包含了方位信息(方法前/后疏日、返回等,但不包含具體的方法信息撒汉,也就是不包含切點信息)
- 目標(biāo)類 Target
- 目標(biāo)類沟优,指的是所要進行增強的類,這個比較好理解
- 引介 Introduction:
- 引介睬辐,一種特殊的增強挠阁,主要作用于類級別上,通常用于為類動態(tài)實現(xiàn)接口等的操作溯饵,也就是作用于類上的增強
- 織入 Weaving
- 織入侵俗,指的是將通過切點信息,將對象的增強添加到目標(biāo)類的過程
- 代理 Proxy
- 代理丰刊,這個比較好理解隘谣,指的就是通過增強之后所產(chǎn)生的對象,也就是原來目標(biāo)類經(jīng)過增強之后的代理類
- 切面 Aspect:
- 切面啄巧,由切點和增強組成寻歧,包含了橫切邏輯和方位的定義,一個切點可以描述多個連接點秩仆,加上增強码泛,就形成了面,也就是所謂的切面了澄耍。
原始的Spring AOP編程方式
這里通過比較原始的Spring AOP編程方式來詳細(xì)講解上面所提到的概念噪珊,以增強對上面的概念的認(rèn)識,需要注意的是齐莲,通過這種方式的目的是為了更好地理解AOP編程的概念卿城,在日常的開發(fā)過程中,由于這種方式比較底層铅搓,而且操作麻煩瑟押,基本是不怎么使用的,還有一點需要注意的是星掰,Spring僅支持方法的增強多望,也就是說,Spring中的切點只能描述方法氢烘,增強只能作用在方法上怀偷。
/**
* 方法調(diào)用前增強
*/
class LogManager implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("log something");
}
}
/**
* UserService接口
*/
interface UserService{
void login();
void logout();
}
/**
* UseService實現(xiàn)類
*/
class UserServiceImpl implements UserService{
@Override
public void login() {
System.out.println("someone login....");
}
@Override
public void logout() {
System.out.println("someone logout....");
}
}
對應(yīng)的Spring配置文件如下
<bean id="userServiceTarget" class="cn.xuhuanfeng.aop.UserServiceImpl"/>
<bean id="advice" class="cn.xuhuanfeng.aop.LogManager"/>
<!--指定代理類,用于為目標(biāo)類進行增強-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置對應(yīng)的目標(biāo)類播玖,也就是要對其進行增強的類-->
<property name="target" ref="userServiceTarget"/>
<!--配置對應(yīng)的增強類-->
<property name="interceptorNames" value="advice"/>
<!--是否使用CGLib動態(tài)代理椎工,如果沒有配置接口,則默認(rèn)是-->
<property name="optimize" value="true"/>
</bean>
測試結(jié)果如下所示
log something
someone login....
log something
someone logout....
從上面的結(jié)果可以看出,我們已經(jīng)成功為UserService的方法配置增強维蒙,并且UserService對此并不知情
接下來再看另外幾個例子
/**
* 方法調(diào)用后增強
*/
class LogManagerAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("after returning");
}
}
/**
* 環(huán)繞增強
*/
class LogManagerAround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("before ...");
Object object = methodInvocation.proceed();
System.out.println("after ...");
return object;
}
}
在配置文件中進行配置的具體代碼基本同上面的內(nèi)容掰吕,這里就不進行展示了,從上面的內(nèi)容可以看出颅痊,如果想對一個對象應(yīng)用AOP方式進行增強殖熟,首先需要為其定義對應(yīng)的增強,同時為其描述對應(yīng)的切點(上面沒有明確指出是切點斑响,所以默認(rèn)是對所有的方法進行增強)菱属,以及對應(yīng)的目標(biāo)類,然后通過Spring的ProxyFactorybean來負(fù)責(zé)進行織入舰罚,產(chǎn)生對應(yīng)的增強類纽门。
不過,從上面的聲明增強的方式中营罢,我們也可以看出通過這種方式配置的缺點
- 只能通過硬編碼指定增強膜毁,并且需要為每個需要增強的類創(chuàng)建增強類
- 無法明確指定切點,只能通過硬編碼進行編寫愤钾,且編寫過程繁瑣
由于通過這種方式的配置有著無法忍受的缺點瘟滨,所以一般我們在實際開發(fā)過程中也沒有這么做,至于一般怎么做能颁,將在后面兩個小節(jié)進行介紹
總結(jié)
由于面向?qū)ο缶幊瘫旧泶嬖谥牟豢杀苊獾膯栴}杂瘸,于是提出了面向切面編程的概念,并且伙菊,隨著前輩們的努力败玉,AOP編程技術(shù)現(xiàn)在已經(jīng)變得非常成熟了。在AOP中編程中镜硕,有幾個比較重要的概念运翼,切點,增強 兴枯,引介血淌,切面,織入财剖,只有對這幾個概念比較熟悉悠夯,才能更好地使用AOP技術(shù)來提高效率,在原始的Spring AOP技術(shù)中躺坟,如果需要聲明一個增強沦补,則需要實現(xiàn)對應(yīng)的接口,這種方式是不太方便的咪橙,因為通過這種方式?jīng)]有辦法明確指定對應(yīng)的切點夕膀,而且基本上必須為需要增強的對象編寫對應(yīng)的增強虚倒,在后面我們將看到,經(jīng)過努力之后的Spring AOP配置方式的簡便性产舞。