Spring AOP實現原理


 

Spring AOP實現原理

AOP實現原理:

 

編織:

1.靜態編織 通過修改源碼或字節碼在編譯器、后編譯器或加載器嵌入代碼

 

2.動態編織 通過代理等技術在運行期實現嵌入。【AspectJ,Spring】

 

 

 

 

一、AOP是什么?

AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)編程,作為面向對象的一種補充,用於處理系統中分布於各個模塊的橫切關注點,比如事務管理、日志、緩存等等。AOP實現的關鍵在於AOP框架自動創建的AOP代理,AOP代理主要分為靜態代理動態代理靜態代理的代表為AspectJ;而動態代理則以Spring AOP為代表。本文會分別對AspectJ和Spring AOP的實現進行分析和介紹。

二、springaop如何實現的?

Spring AOP中的動態代理主要有兩種方式JDK動態代理CGLIB動態代理。JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個接口。JDK動態代理的核心InvocationHandler接口和Proxy類。

如果目標類沒有實現接口,那么Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成某個類的子類,注意,CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態代理的。

2.1、JDK動態代理

定義一個接口類

package org.java.base.springaop;
public interface Service {
 /**
 * add方法
 */
 public void add();

 /**
 * update方法
 */
 public void update();
}復制代碼

實現一個接口類

package org.java.base.springaop;
public class ServiceImpl implements Service {
 
 public void add() { System.out.println("AService add>>>>>>>>>>>>>>>>>>"); } public void update() { System.out.println("AService update>>>>>>>>>>>>>>>"); } }復制代碼

實現動態代理類MyInvocationHandler,實現InvocationHandler接口,並且實現接口中的invoke方法。仔細看invoke方法,就是在該方法中加入切面邏輯的。目標類方法的執行是由mehod.invoke(target,args)這條語句完成。

package org.java.base.springaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
 private Object target;
 /**
 * 構造函數
 * @param target
 */
 MyInvocationHandler(Object target) {
 super();
 this.target = target;
 }
 public Object invoke(Object proxy, Method method, Object[] args)
 throws Throwable {
 // 程序執行前加入邏輯,MethodBeforeAdviceInterceptor
 System.out.println("before-----------------------------"); // 程序執行 Object result = method.invoke(target, args); // 程序執行后加入邏輯,MethodAfterAdviceInterceptor System.out.println("after------------------------------"); return result; } }復制代碼

測試類,其中增強的目標對象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(),aService.getClass().getInterfaces(), handler);來生成的。

package org.java.base.springaop;

import java.lang.reflect.Proxy;
public class Test {
 public static void main(String[] args) {
 Service aService = new ServiceImpl();
 MyInvocationHandler handler = new MyInvocationHandler(aService);
 // Proxy為InvocationHandler實現類動態創建一個符合某一接口的代理實例
 Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
 .getClass().getClassLoader(), aService.getClass()
 .getInterfaces(), handler);
 // 由動態生成的代理對象來aServiceProxy 代理執行程序,其中aServiceProxy 符合Service接口
 aServiceProxy.add();
 System.out.println();
 aServiceProxy.update();
 
 }
}復制代碼

1525849940(1)

可以看到,在目標類ServiceImpl的add和update方法前后已經加入了自定義的切面邏輯,AOP攔截機制生效了。

2.2、CGLIB動態代理

目標類,cglib不需要定義目標類的統一接口

package org.java.base.springaop;

public class Base {
 /**
 * 一個模擬的add方法
 */
 public void add() { System.out.println("add ------------"); } }復制代碼

實現動態代理類CglibProxy,需要實現MethodInterceptor接口,實現intercept方法。該代理中在add方法前后加入了自定義的切面邏輯,目標類add方法執行語句為proxy.invokeSuper(object, args);

package org.java.base.springaop;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {

 public Object intercept(Object object, Method method, Object[] args,
 MethodProxy proxy) throws Throwable {
 // 添加切面邏輯(advise),此處是在目標類代碼執行之前,即為MethodBeforeAdviceInterceptor。
 System.out.println("before-------------"); // 執行目標類add方法 proxy.invokeSuper(object, args); // 添加切面邏輯(advise),此處是在目標類代碼執行之后,即為MethodAfterAdviceInterceptor。 System.out.println("after--------------"); return null; } }復制代碼

獲取增強的目標類的工廠Factory,其中增強的方法類對象是有Enhancer來實現的,代碼如下所示:

 package org.java.base.springaop;

import org.springframework.cglib.proxy.Enhancer;

public class Factory {
 /**
 * 獲得增強之后的目標類,即添加了切入邏輯advice之后的目標類
 * 
 * @param proxy
 * @return */ public static Base getInstance(CglibProxy proxy) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Base.class); //回調方法的參數為代理類對象CglibProxy,最后增強目標類調用的是代理類對象CglibProxy中的intercept方法 enhancer.setCallback(proxy); // 此刻,base不是單純的目標類,而是增強過的目標類 Base base = (Base) enhancer.create(); return base; } }復制代碼

測試類

package org.java.base.springaop;

public class Testcglib {
 public static void main(String[] args) {
 CglibProxy proxy = new CglibProxy();
 // base為生成的增強過的目標類
 Base base = Factory.getInstance(proxy);
 base.add();
 }
}復制代碼

自此,cglib動態代理實現的AOP攔截機制已經基本實現,下面我們來看一下攔截的效果如何,程序執行結果如下:

before————-
add ————
after————–

可以看到,在目標類Base的add方法前后已經加入了自定義的切面邏輯,AOP攔截機制生效了。

三、關於動態代理和CGLIB這兩種方式的簡要總結如下:

  • JDK動態代理(Dynamic Proxy)
    • 基於標准JDK的動態代理功能
    • 只針對實現了接口的業務對象
  • CGLIB
    • 通過動態地對目標對象進行子類化來實現AOP代理,
    • 需要指定@EnableAspectJAutoProxy(proxyTargetClass = true)來強制使用
    • 當業務對象沒有實現任何接口的時候默認會選擇CGLIB摘自 https://juejin.im/post/5af3bd6f518825673954bf22
      • 摘自 https://juejin.im/post/5af3bd6f518825673954bf22


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM