AOP(Aspect Orient Programming),咱們通常稱爲面向方面(切面)編程,做爲面向對象的一種補充,用於處理系統中分佈於各個模塊的橫切關注點,好比事務管理、日誌、緩存等等。AOP實現的關鍵在於AOP框架自動建立的AOP代理,AOP代理主要分爲靜態代理和動態代理,靜態代理的表明爲AspectJ;而動態代理則以Spring AOP爲表明。本文會分別對AspectJ和Spring AOP的實現進行分析和介紹。java
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理經過反射來接收被代理的類,而且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler
接口和Proxy
類。spring
若是目標類沒有實現接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,能夠在運行時動態的生成某個類的子類,注意,CGLIB是經過繼承的方式作的動態代理,所以若是某個類被標記爲final
,那麼它是沒法使用CGLIB作動態代理的。編程
定義一個接口類緩存
package org.java.base.springaop;
public interface Service {
/**
* add方法
*/
public void add();
/**
* update方法
*/
public void update();
}複製代碼
實現一個接口類bash
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();
}
}複製代碼
能夠看到,在目標類ServiceImpl的add和update方法先後已經加入了自定義的切面邏輯,AOP攔截機制生效了。post
目標類,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);ui
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攔截機制生效了。
@EnableAspectJAutoProxy(proxyTargetClass = true)
來強制使用