国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java學習之:JDK動態代理與CGLIB動態代理

2019-11-14 23:13:13
字體:
來源:轉載
供稿:網友
java學習之:JDK動態代理與CGLIB動態代理

代理的概念:簡單的理解就是通過為某一個對象創建一個代理對象,我們不直接引用原本的對象,而是由創建的代理對象來控制對原對象的引用。

動態代理:是指在程序運行時由Java反射機制動態生成,無需手動編寫代碼。動態代理不僅簡化了編程工作,而且提高了軟件系統的可擴展性,因為Java反射機制可以生成任意類型的動態代理類。

代理原理:代理對象內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當于對真實對象進行封裝。

以下通過一個簡單的例子來看基于JDK動態代理與CGLIB分別如何實現代理。

代理接口UserService:

1 package com.liang.test;2 3 public interface UserService {4     public void say(String arg);5 }

UserService實現類UserServiceImpl:

1 package com.liang.test;2 3 public class UserServiceImpl implements UserService {4     @Override5     public void say(String arg) {6         System.out.

JDK通過java.lang.reflect包下的Proxy類和一個InvocationHandler接口來生成動態代理類和動態代理對象。

首先創建一個實現InvocationHandler接口的調用控制器對象MyInvocationHandler:(當執行動態代理對象里的目標方法時,實際上會替換成調用MyInvocationHandler的invoke方法)

 1 package com.liang.test; 2  3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5  6 public class MyInvocationHandler implements InvocationHandler { //實現InvocationHandler 7  8     private Object object; //被代理對象 9     10     public MyInvocationHandler(Object object){ //接收被代理對象11         this.object = object;12     }13     @Override14     public Object invoke(Object proxy, Method method, Object[] args)15             throws Throwable { //say()方法被替換執行成當前方法,可在其中添加額外功能增強目標方法16         System.out.println("before method");17         Object obj = method.invoke(object, args); //通過反射調用UserService的say()方法18         System.out.println("after method");19         return obj;20     }21 22 }

通過Proxy結合MyInvocationHandler為UserService創建動態代理類:

 1 package com.liang.test; 2  3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5  6 public class TestProxy { 7  8     public static void main(String[] args) { 9         UserService userService = new UserServiceImpl();10         InvocationHandler handler = new MyInvocationHandler(userService);11 12         UserService proxy = (UserService)Proxy.newProxyInstance(userService.getClass()13                 .getClassLoader(), userService.getClass().getInterfaces(),14                 handler);15         proxy.say("孫悟空"); //調用代理實例16     }17 18 }

運行結果:

before methodhello, I am 孫悟空after method

可以看到執行代理實例的say方法時執行的是MyInvocationHandler的invoke()方法。

而CGLIB則是采用非常底層的字節碼技術,為被代理對象創建一個子類,并在子類中采用方法攔截的技術攔截所有父類方法的調用,并順勢植入增強代碼。CGLIB實現動態代理的示例如下:

 1 package com.liang.test; 2  3 import java.lang.reflect.Method; 4  5 import net.sf.cglib.proxy.Enhancer; 6 import net.sf.cglib.proxy.MethodInterceptor; 7 import net.sf.cglib.proxy.MethodProxy; 8  9 public class CglibProxy implements MethodInterceptor {10     11     private Enhancer enhancer = new Enhancer();12 13     public Object getProxy(Class clazz) {14         enhancer.setSuperclass(clazz); // 設置需要創建子類的類15         enhancer.setCallback(this);16         return enhancer.create();// 創建子類實例17     }18 19     @Override20     public Object intercept(Object object, Method method, Object[] args,21             MethodProxy proxy) throws Throwable { //攔截父類中所有的方法調用22         System.out.println("cglib: before method");23         Object obj = proxy.invokeSuper(object, args); //通過代理類調用父類中的方法24         System.out.println("cglib: after method");25         return obj;26     }27 28 }

測試代碼:

 1 package com.liang.test; 2  3 public class TestProxy { 4  5     public static void main(String[] args) { 6         CglibProxy proxy = new CglibProxy(); 7         UserServiceImpl userServiceImpl = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class); 8         userServiceImpl.say("孫悟空"); 9     }10 11 }

運行結果:

cglib: before methodhello, I am 孫悟空cglib: after method

小結:JDK動態代理與CGLIB動態代理最常見的應用是SpringAOP的底層實現,基于JDK的動態代理在創建代理對象時所花費的時間比CGLIB短,但是JDK只能為接口創建代理實例,這一點可以從newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)中看出:第二個入參就是代理示例實現的接口列表。而CGLIB創建的代理對象性能比JDK創建的代理對象高,但是花費的時間相對長一些,并且由于CGLIB采用動態創建子類的方式生成代理對象,所以對于由final修飾的方法不能通過CGLIB進行代理。基于此,我們對于singgleton的代理對象或者具有實例池的代理比較適合使用CGLIB動態代理技術,對于每次都要new出新實例的一般采用JDK的動態代理技術。

本次學習資料參照了:

  1.《精通Spring2.x-企業應用開發詳解》——陳雄華著;

  2.http://rejoy.VEvb.com/blog/1627405——JDK動態代理實現原理

        


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 石楼县| 沁阳市| 吉安县| 江源县| 天镇县| 岳普湖县| 贵州省| 全椒县| 板桥市| 九江市| 清远市| 普兰县| 峡江县| 寻乌县| 博爱县| 宝山区| 泸西县| 涪陵区| 宝清县| 大足县| 乌兰察布市| 元阳县| 嵩明县| 建昌县| 双桥区| 满城县| 松江区| 扎兰屯市| 辉县市| 都匀市| 陇南市| 清原| 仁怀市| 全南县| 安宁市| 吉林省| 大洼县| 新野县| 巴中市| 蒙自县| 新丰县|