Spring AOP 代理實現的兩種方式: JDK動態代理 和 Cglib框架動態代理
阿新 • • 發佈:2018-12-30
1.JDK動態代理
JDK API 內建 ---- 通過 Proxy類,為目標物件建立代理 (必須面向介面代理 ),此文中介面為UserDao,實現類為UserDaoImpl.
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("儲存方法執行");
}
}
下面為目標物件target(UserDaoImpl)建立代理的工廠:
下面為測試類,為UserDaoImpl建立代理物件,對用代理物件執行UserDaoImpl中的方法import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JdkProxyFactory{ //被代理的物件 private Object target; public JdkProxyFactory(Object target) { this.target = target; } /** * 用於建立target的代理物件 * @return */ public Object createProxy(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //執行增強的方法 System.out.println("方法增強了"); //執行被代理物件的真正方法 return method.invoke(target, args); } }); } }
public class JdkProxyTest { @Test public void testUseProxy(){ //代理之前的物件 UserDao userDao = new UserDaoImpl(); //代理之後的物件 UserDao userDaoProxy = (UserDao) new JdkProxyFactory(userDao).createProxy(); System.out.println(userDaoProxy); userDaoProxy.save(); } }
缺點: 使用Jdk動態代理,必須要求target目標物件,實現介面 ,如果沒有介面,不能使用Jdk動態代理
2.Cglib 動態代理
CGLIB(CodeGeneration Library)是一個開源專案!是一個強大的,高效能,高質量的Code生成類庫,它可以在執行期擴充套件Java類與實現Java介面。
Cglib 不但可以對介面進行代理,也可以對目標類物件,實現代理(解決了 Jdk 只能對介面代理問題 )。在spring3.2版本 core包中內建cglib 類。
下面為ProductDao使用cglib為其建立代理物件
public class ProductDao { public void saveProdcut(){ System.out.println("產品儲存"); } }
建立代理物件的工廠:
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* 使用cglib進行代理 --- 工廠類
*
*/
public class CglibProxyFactory implements MethodInterceptor {
// 被代理目標物件
private Object target;
// 在構造工廠時傳入被代理物件
public CglibProxyFactory(Object target) {
this.target = target;
}
// 建立代理物件方法
public Object createProxy() {
// 1、 建立Enhancer物件
Enhancer enhancer = new Enhancer();
// 2、 cglib建立代理,對目標物件,建立子類物件
enhancer.setSuperclass(target.getClass());
// 3、傳入 callback物件,對目標增強
enhancer.setCallback(this);
return enhancer.create();
}
@Override
/**
* proxy 代理物件
* method 當前呼叫方法
* args 方法引數
* methodProxy 被呼叫方法代理物件 (作用:執行父類的方法)
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("記錄日誌......");
// 按照JDK程式設計
// return method.invoke(target, args);
return methodProxy.invokeSuper(proxy, args);
}
}
下面為測試類:
import org.junit.Test;
public class CglibProxyTest {
@Test
public void test(){
ProductDao productDao = new ProductDao();
ProductDao productDaoProxy = (ProductDao) new CglibProxyFactory(productDao).createCglibProxy();
productDaoProxy.saveProdcut();
}
}
執行結果如下:
Cglib 建立代理思想:對目標類建立子類物件
設定 superClass 對哪個類建立子類 (類似 JDK代理 介面)
設定 callback 實現增強程式碼 (類似 JDK代理InvocationHandler )
在cglib的callback函式中,要執行被代理物件的方法
method.invoke(target,args); 等價於 methodProxy.invokeSuper(proxy,args);
優先對介面代理(使用JDK代理),如果目標沒有介面,才會使用cglib代理!