如果目標(biāo)類實(shí)現(xiàn)接口,采用JDK動態(tài)代理;如果目標(biāo)類沒有實(shí)現(xiàn)接口,采用CGLIB動態(tài)代理
一.JDK動態(tài)代理
//JDK動態(tài)代理
public class SomeServiceTest {
@Test
public void someServiceTest(){
SomeService target = new SomeServiceImpl();
//loader:一個ClassLoader對象,定義了由哪個ClassLoader對象來生成代理對象進(jìn)行加載
//interfaces:一個Interface對象的數(shù)組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實(shí)現(xiàn)了該接口(多態(tài)),這樣我就能調(diào)用這組接口中的方法了
//h:一個InvocationHandler對象,表示的是當(dāng)我這個動態(tài)代理對象在調(diào)用方法的時候,會關(guān)聯(lián)到哪一個InvocationHandler對象上,間接通過invoke來執(zhí)行
SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),//目標(biāo)類的類加載器
target.getClass().getInterfaces(),//目標(biāo)類實(shí)現(xiàn)的所有接口
new InvocationHandler() {//調(diào)用處理器
/**
* proxy:代理對象
* method:目標(biāo)方法
* args:目標(biāo)方法的參數(shù)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SomeServiceUtil.doTransaction();
//執(zhí)行目標(biāo)方法 (注意invoke中的第一個參數(shù)寫的是被代理對象)
Object result = method.invoke(target, args);
SomeServiceUtil.doLog();
return result;
}
});
//通過代理對象調(diào)用方法
proxy.doSome();
}
總結(jié)
1.JDK內(nèi)置的Proxy動態(tài)代理可以在運(yùn)行時動態(tài)生成字節(jié)碼,而沒必要針對每個類編寫代理類。中間主要使用到了一個接口InvocationHandler與Proxy.newProxyInstance靜態(tài)方法;
2.使用內(nèi)置的Proxy實(shí)現(xiàn)動態(tài)代理有一個問題:被代理的類必須實(shí)現(xiàn)接口,未實(shí)現(xiàn)接口則沒辦法完成動態(tài)代理。
3.如果項(xiàng)目中有些類沒有實(shí)現(xiàn)接口,則不應(yīng)該為了實(shí)現(xiàn)動態(tài)代理而刻意去抽出一些沒有實(shí)例意義的接口,通過cglib可以解決該問題。
二.CGLIB動態(tài)代理
CGLIB(Code Generation Library)是一個開源項(xiàng)目,是一個強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫,它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口,通俗說cglib可以在運(yùn)行時動態(tài)生成字節(jié)碼。
使用cglib完成動態(tài)代理,大概的原理是:cglib繼承被代理的類,重寫方法,織入通知,動態(tài)生成字節(jié)碼并運(yùn)行,因?yàn)槭抢^承所以final類是沒有辦法動態(tài)代理的
package com.zhangguo.Spring041.aop04;
import java.lang.reflect.Method;
import java.util.Random;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
* 動態(tài)代理類
* 實(shí)現(xiàn)了一個方法攔截器接口
*/
public class DynamicProxy implements MethodInterceptor {
// 被代理對象
Object targetObject;
//Generate a new class if necessary and uses the specified callbacks (if any) to create a new object instance.
//Uses the no-arg constructor of the superclass.
//動態(tài)生成一個新的類,使用父類的無參構(gòu)造方法創(chuàng)建一個指定了特定回調(diào)的代理實(shí)例
public Object getProxyObject(Object object) {
this.targetObject = object;
//增強(qiáng)器,動態(tài)代碼生成器
Enhancer enhancer=new Enhancer();
//回調(diào)方法
enhancer.setCallback(this);
//設(shè)置生成類的父類類型
enhancer.setSuperclass(targetObject.getClass());
//動態(tài)生成字節(jié)碼并返回代理對象
return enhancer.create();
}
// 攔截方法
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 被織入的橫切內(nèi)容,開始時間 before
long start = System.currentTimeMillis();
// 調(diào)用方法
Object result = methodProxy.invoke(targetObject, args);
// 被織入的橫切內(nèi)容,結(jié)束時間
Long span = System.currentTimeMillis() - start;
System.out.println("共用時:" + span);
return result;
}
}
總結(jié):
使用cglib可以實(shí)現(xiàn)動態(tài)代理,即使被代理的類沒有實(shí)現(xiàn)接口,但被代理的類必須不是final類。