淺談java中的cglib代理
阿新 • • 發佈:2019-02-13
什麼是cglib代理?
定義:cglib代理,也叫做子類代理。在記憶體中構建一個子類物件從而實現對目標物件功能的擴充套件。
上一篇部落格
物件必須實現至少一個介面。那麼如果被代理的物件想要拓展功能,但又沒有實現介面,該怎麼辦呢?
我們就可以使用cglib代理來解決了。
CGLIB是一個強大的高效能的程式碼生成包,它可以在執行期擴充套件Java類與實現Java介面。它廣泛的被許多AOP的框架
使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)。
CGLIB包的底層是通過使用一個小而快的位元組碼處理框架ASM,來轉換位元組碼並生成新的類。不鼓勵直接使用ASM,
因為它要求你必須對JVM內部結構包括class檔案的格式和指令集都很熟悉。
Cglib子類代理:
1) 需要引入cglib – jar檔案, 但是spring的核心包中已經包括了cglib功能,我這裡引入spring-core-3.2.5.jar。
2)引入功能包後,就可以在記憶體中動態構建子類
3)代理的類不能為final, 否則報錯。
4) 目標物件的方法如果為final/static, 那麼就不會被攔截,即不會執行目標物件額外的業務方法。
下面我們通過程式碼來說明一下
首先建立一個UserDao類,類裡面有save和update兩個方法
public class UserDao { public void save(){ System.out.println("資料已經儲存"); } public void update(){ System.out.println("資料已經更新"); } }
再建立一個CglibProxyFactory類,實現org.springframework.cglib.proxy.MethodProxy介面
在CglibProxyFactory類中需要通過Enhancer類建立子類代理物件
import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; /** * cglib子類代理工廠 對UserDao在記憶體中動態構建一個子類物件 * * @author wangchaoyouziying * */ public class CglibProxyFactory implements MethodInterceptor { private Object target;// 被代理物件 public CglibProxyFactory(Object target) { this.target = target; } /** * 建立代理物件 * * @return */ public Object getProxyInstance() { Enhancer enhancer = new Enhancer(); // 設定父類 enhancer.setSuperclass(target.getClass()); // 設定回撥函式 enhancer.setCallback(this); // 建立子類(代理物件) return enhancer.create(); } /** * obj 代理物件 * method 被代理物件的方法 * args 被代理物件的引數 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if ("save".equals(method.getName())) {//這裡只改造被代理物件的save方法 System.out.println("開始事務"); // 執行被代理物件的方法 Object invoke = method.invoke(target, args); System.out.println("提交事務"); return invoke; }else{//其餘方法按原樣執行 return method.invoke(target, args); } } }
測試一下
public class Test {
public static void main(String[] args) {
//被代理物件
UserDao userDao = new UserDao();
//class cn.chao.cglibProxy.UserDao
System.out.println(userDao.getClass());
//代理物件
UserDao proxy = (UserDao) new CglibProxyFactory(userDao).getProxyInstance();
//UserDao的子類 class cn.chao.cglibProxy.UserDao$$EnhancerByCGLIB$$e6c21b2c
System.out.println(proxy.getClass());
//執行代理物件的方法
proxy.save();
proxy.update();
}
}
執行結果:
class cn.chao.cglibProxy.UserDao
class cn.chao.cglibProxy.UserDao$$EnhancerByCGLIB$$e6c21b2c
開始事務
資料已經儲存
提交事務
資料已經更新