Spring AOP 實現機制

1. AOP概念

1.1 JoinPoint連接點:程序執行中的特定點,如方法執行,調用構造函數或字段復制等,面向切面編程,JoinPoint就是要被切入的對象。??

1.2 Advice通知:在一個連接點中,切面采取的行動,針對切入點,要做的事情。?

1.3?Pointcut切點:一個匹配連接點的正則表達式。每個任何連接點匹配一個切入點時,就執行與該切入點相關聯的指定通知。關注哪些被切入點可以切入。?

1.4?Aspect切面(Advisor):一個分布在應用程序中多個位置的標準代碼/功能,通常與實際的業務邏輯(例事務管理)不同。每個切面都側重于一個特定的橫切功能。

1.5?Weaving織入:鏈接切面和目標對象來創建一個通知對象的過程。

1.6 Advice通知 + Pointcut切點形成了切面Aspect/Advisor

1.7 JoinPoint與Pointcut區別:在Spring AOP中,所有方法執行都是JoinPoint。Pointcut是描述信息,修飾的是JoinPoint,通過Pointcut就可以確定哪些JoinPoint可以織入Advice,JointPoint與Pointcut本質上兩個不同的緯度。Advice是在JointPoint執行,Pointcut確定了哪些JoinPoint執行Advice。

2. AOP實現

2.1 織入節點

????編譯期間:切面在目標類編譯時被織入,需要引入獨立的編譯器。

? ? 編譯后:增強已經編譯出來的類,如我們要增強依賴的 jar 包中的某個類的某個方法。

? ? 類加載期:在 JVM 進行類加載的時候進行織入。

? ? 運行期:切面在應用運行的某個時期被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態創建一個代理對象。

2.2 實現框架

? ? AspectJ:AspectJ 是一個采用Java 實現的AOP框架,它能夠對代碼進行編譯(一般在編譯期進行),讓代碼具有AspectJ 的 AOP 功能,AspectJ 是目前實現 AOP 框架中最成熟,功能最豐富的語言。ApectJ 主要采用的是編譯期靜態織入的方式。

? ? AspectWerkz:基于Java的簡單、動態、輕量級、強大的AOP框架。可以在運行時或編譯時輕松的改造任何(舊)應用程序或除了rt.jar以外的外部類庫。

? ? JBoss AOP:JBoss 4.0帶了一個AOP框架。這個框架和JBoss應用服務器緊密地結合,但是也能夠在應用中單獨運行它。

? ? Spring AOP:Spring AOP 是通過動態代理技術實現的,而動態代理是基于反射設計的。Spring AOP 采用了兩種混合的實現方式:JDK 動態代理和 CGLib 動態代理

2.3 AspectJ 與 Spring AOP比較


3. AspectJ實現

AspectJ是提供了完整的AOP方案,采用靜態織入,不依賴Spring AOP。

3.1 定義切面

針對test()方法進行攔截,方法執行前打印"before interceptor"

@Aspect

public class AspectjInterceptor {

????@Pointcut("execution( * com.hobbit.aspectj.Hello.test())")

????public void execute(){

????}

????@Before("execute()")

????public void beforeLog(){

????????System.out.println("before interceptor");

? ? }

}

3.2 主任務

@Component

public class Hello {

????public void test(){

????????System.out.println("hello aspectj");

? ? }

}

3.3 設置編譯器

Java Compiler -> User compiler 選擇Ajc,同時設置aspectjtools.jar,見下圖


3.4 運行結果

3.5 反編譯文件


4. Spring AOP創建代理

spring aop既可以使用AspectJ注解實現攔截,也可以不依賴AspectJ,使用Spring advice + pointcut,實現攔截注入。

tip: spring aop 使用AspectJ注解時,攔截實現方式是?

4.1 使用AspectJ注解

4.1.1 定義元注解

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface LogAnnotation {

????????Stringvalue();

}

4.1.2 定義切面

@Aspect

@Component

public class LogInterceptor {

@Pointcut("@annotation(com.hobbit.interceptor.LogAnnotation)")

public void annotationPointCut(){

}

@Before("annotationPointCut()")

public void beforeLog(JoinPoint joinPoint){

????????MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

? ? ? ? LogAnnotation logAnnotation = methodSignature.getMethod().getAnnotation(LogAnnotation.class);

? ? ? ? if(Objects.nonNull(logAnnotation)){

? ? ? ? ?????System.out.println("beforeLog : " + logAnnotation.value());

? ? ? ? }

????}

}

4.1.3 織入

@Service

public class UserService {

????@Autowired

? ? private UserMapperuserMapper;


????@LogAnnotation("queryUser")

? ? public UserEntityqueryUser(int id){

????????return userMapper.getById(id);

? ? }

}

tip:使用Aspect切面時,底層使用AspectJ實現的靜態織入,還是有Spring AOP實現的動態織入?

4.2 Spring AOP實現

Spring AOP實現了完整的方案,通過定義advice + pointcut 實現對象動態織入。

4.2.1 定義Advice

public class LogBeforeAdviceimplements MethodBeforeAdvice {? ??

????@Override

? ? public void before(Method method, Object[] args, Object target)throws Throwable{

????????System.out.println("before advice for class:" + target.getClass() +" and method:" + method.getName());

? ? }

}

4.2.2 配置PointCut及切面

? ??<bean id="logBeforeAdvice" class="com.hobbit.interceptor.LogBeforeAdvice"></bean>

????<bean id="logPointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">

? ???????? <property name="pattern" value="com.hobbit.service.ShowService.show"/>

? ? </bean>

????<bean id="logAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">

? ???????? <property name="advice" ref="logBeforeAdvice">

? ???????? <property name="pointcut" ref="logPointCut">

????</bean>

4.2.3 通過ProxyFactoryBean創建代理

<bean id="showProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

? ???? <property name="target" ref="showService">

? ? ? ?<property name="interceptorNames" value="logAdvisor">

? ???? <property name="proxyInterfaces" value="com.hobbit.service.ShowInterface">

</bean>

4.3? 創建代理時序圖

Spring的代理對象通過Bean的后置處理器,在createBean對象時封裝的。創建的代理的時序圖如下

5. Spring AOP生效

5.1 Spring 創建代理的節點

Spring 通過org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization實現AspectJ注解代理對象的創建,具體在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization實現代理對象的創建

代理對象創建前


創建代理對象


5.2 Spring AOP攔截

? ? ? ?Spring AOP通過把Advice轉化成MethodIntercetor,通過遞歸調用的方式實現了Advice的織入,完成advice的調用后,調用目標方法完成切入。

? ? ? ?目標對象:ReflectiveMethodInvocation,在JdkDynamicAopProxy invoke方法中創建,是JoinPiont的一個實現。


? ? ? ? 攔截對象:MethodInterceptor.invoke(MethodInvocation invocation)包括了要攔截的對象。實現不同形式的攔截


? 事務攔截TransactionInterceptor

?? tip:先調用攔截鏈,如何時間后置攔截?Interceptor異常是否會導致事務切面回滾?

5.3 總結

Spring的AOP實現并不依賴于AspectJ任何類,它自己實現了一套AOP的。比如它Spring自己提供的BeforeAdvice和AfterAdvice都是對AOP聯盟規范的標準實現。以及Spring自己抽象出來的對Advice的包裝:org.springframework.aop.Advisor貫穿Spring AOP的始終。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375