關於JDK動態代理和cglib動態代理
在spring AOP中,由於通知類中抽取了原始物件中的公共方法,使得原始物件的方法變得不能進行完整的操作。但是我們還是想通過某個方式實現原始物件完成完整操作,我們可以通過為原始物件建立代理物件的方式達到目的,有兩種方式:JDK動態代理和cglib動態代理。
一、JDK動態代理
1、概述:針對記憶體中的Class物件,使用類載入器,動態為目標物件的實現介面建立代理物件。也就是說JDK代理是對物件做代理。
2、具體實現(如下程式碼):
建立一個介面及實現類
public interface UserDao {
public void add();
}
public class UserDaoImp implements UserDao {
@Override
public void add() {
System.out.println("新增使用者操作");
}
}
建立實現JDK動態代理的工具類
public class JdkProxy implements InvocationHandler {
private UserDao userDao;
// 定義一個方法用於建立JDK代理物件
public UserDao createProxyObject(UserDao userDao) {
// 被代理物件作為引數傳入進來
this.userDao = userDao;
// 獲取類載入器:對誰代理,使用誰的類載入器
ClassLoader classLoader = userDao.getClass().getClassLoader();
// 獲取被代理物件的所有實現介面
Class<?>[] interfaces = userDao.getClass().getInterfaces();
// 建立Handler物件,用於增強攔截,為了方便呼叫使用實現InvocationHandler介面的方式
InvocationHandler h = this;
Object obj = Proxy.newProxyInstance(classLoader, interfaces, h);
return (UserDao) obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("連線資料庫");// 增強操作
// 對原始操作進行呼叫(使用反射)
method.invoke(userDao, args);
System.out.println("關閉資料庫");
return null;
}
public static void main(String[] args) {
// 1、建立一個物件
UserDao dao = new UserDaoImp();
// 2、為原始物件建立代理物件
UserDao daoProxy = new JdkProxy().createProxyObject(dao);
// 3、使用代理物件執行操作
daoProxy.add();
}
}
二、cglib動態代理
1、概述:非介面實現的物件,對於不使用介面的業務類,無法使用JDK動態代理。cglib採用底層位元組碼急速,可以為一個類建立子類,也就是cglib是解決無介面代理問題,
是對類做代理。
2、具體實現(如下程式碼)
建立Person類及生成代理的方法
public class Person {
public void action() {
System.out.println("Java程式設計師");
}
}
public Person createProxyObject(Class clazz) {
// cglib中的核心物件是Enhance,用來在記憶體中建立一段動態的類的位元組碼
Enhancer enhancer = new Enhancer();//此時沒有做繼承
// 為其指定父類,除了完成繼承關係外,還將父類所有的方法反射過來,並在自己的類中建立這些方法
enhancer.setSuperclass(clazz);
// 進行功能的增強
// 設定方法的呼叫攔截
Callback callback = new MethodInterceptor() {
// proxy:代理物件
// method:被攔截的方法物件
// args:呼叫函式
// methodProxy:使用代理機制建立被代理物件的方法
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
// 做增強
System.out.println("Java後端程式設計師還會烤肉");
// 呼叫原始的操作
Object ret = methodProxy.invokeSuper(proxy, args);
return ret;
}
};
// 設定具體的回撥操作
enhancer.setCallback(callback);
// 建立記憶體中全新類的物件
Object proxyObj = enhancer.create();
return (Person) proxyObj;
}
3、小結:cglib動態代理機制其實是利用繼承的思想來實現,在程式碼中可以看出,代理機制建立代理物件,把被代理的物件當做父類,把代理的物件
當做子類,走父類執行,走子類的實現,這體現了繼承與多型的思想。
三、總結
cglib可以對任意的類進行代理,JDKdial只能對介面實現的類進行代理。