本篇記錄下Spring AOP的兩種代理,為下一篇AOP實現做下鋪墊。
1.JDK動態代理 2.cglib代理
1、如果目標對象實現了接口,默認情況下會采用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須采用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
注:JDK動態代理要比cglib代理執行速度快,但性能不如cglib好。所以在選擇用哪種代理還是要看具體情況,一般單例模式用cglib比較好,具體原因請自行百度。
一。JDK動態代理實現(原理是使用反射機制)
首先定義接口,並實現
public interface TestService{
public int add();
}
public class TestServiceImpl implements TestService{
@Override
public int add() {
System.out.println("開始執行add...");
return 0;
}
}
定義代理類,這裡要注意導入的包是import java.lang.reflect.*
public class JDKDynamicProxy implements InvocationHandler {
//被代理的目標對象
private Object proxyObj;
/**
* Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
* loader :類加載器 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
* interfaces:一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什麼接口,如果我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了
* h :一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上
*/
public Object newProxy(Object proxyObj){
this.proxyObj = proxyObj;
//返回一個代理對象
return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),
proxyObj.getClass().getInterfaces(),
this);
}
/**
* 執行目標對象
* Object proxy:被代理的對象
* Method method:要調用的方法
* Object args[]:方法調用時所需要的參數
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
before();
Object object = method.invoke(this.proxyObj,args); // 通過反射機制調用目標對象的方法
after();
return object;
}
public void before(){
System.out.println("開始執行目標對象之前...");
}
public void after(){
System.out.println("開始執行目標對象之後...");
}
}
測試類:
public static void main(String[] args) {
//我們要代理的真實對象
TestService testService = new TestServiceImpl();
//testJDKProxyService.add();//不是用代理
JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy();
TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService);
//執行代理類的方法
testServiceProxy.add();
}
控制台顯示
二。CGLIB代理,需要導入 cglib-nodep-2.1_3.jar
先說下cglib,CGlib是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。
先定義一個實現類(注意並沒有實現接口)
public class TestCGLIBServiceImpl {
public int add() {
System.out.println("開始執行add...");
return 0;
}
}
定義cglib代理類,此時導入的包應該是import net.sf.cglib.proxy.*
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGLIBProxy implements MethodInterceptor{
private Object targetObject ;//被代理的目標對象
public Object createProxyInstance(Object targetObject) {
this . targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());// 設置代理目標
enhancer.setCallback( this );// 設置回調
return enhancer.create();
}
/**
* 在代理實例上處理方法調用並返回結果
* @param object : 代理類
* @param method :被代理的方法
* @param args :該方法的參數數組
* @param methodProxy
*/
@Override
public Object intercept(Object object, Method method, Object[] args,
MethodProxy methodproxy) throws Throwable {
Object result = null;
try {
System. out .println( "前置處理開始 ..." );
result = methodproxy.invoke( targetObject , args);//執行目標對象的方法
System. out .println( "後置處理開始 ..." );
} catch (Exception e) {
System. out .println( " 異常處理 ..." );
} finally {
System. out .println( " 調用結束 ..." );
}
return result;
}
}
測試類:
public class TestCGLIBProxy {
public static void main(String[] args) {
//我們要代理的真實對象
TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl();
CGLIBProxy CGLIBproxy = new CGLIBProxy();
TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB);
testCGLIBProxy.add();
}
}
結果圖:
寫在後面:spring AOP的兩種代理實現代碼就寫到這,這裡只是實現了,如果你要想真正明白,還得熟悉其中原理機制,比如反射機制,newProxyInstance(...),Enhancer()原理,invoke()原理等等。
下一篇將要記錄spring AOP的基於注解的具體實現(見 http://www.linuxidc.com/Linux/2015-11/125018.htm),而對於XML的我姑且不是用了,因為不夠靈活,不夠強大,要是有時間還會介紹下spring AOP 自定義注解的實現。
Spring AOP進行日志記錄 http://www.linuxidc.com/Linux/2015-11/124731.htm
使用Spring AOP進行性能監控 http://www.linuxidc.com/Linux/2012-07/64681.htm
利用Spring AOP 更新Memcached 緩存策略的實現 http://www.linuxidc.com/Linux/2012-03/56503.htm