zoukankan      html  css  js  c++  java
  • 【Java深入研究】6、CGLib动态代理机制详解

    一、首先说一下JDK中的动态代理

    JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的

    但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。

    二、使用CGLib实现

    使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

    下面,将通过一个实例介绍使用CGLib实现动态代理。

    1、被代理类

    首先,定义一个类,该类没有实现任何接口,包含两个方法。

    Java代码  收藏代码
    1. public class ConcreteClassNoInterface {  
    2.     public String getConcreteMethodA(String str){  
    3.         System.out.println("ConcreteMethod A ... "+str);  
    4.         return str;  
    5.     }  
    6.     public int getConcreteMethodB(int n){  
    7.         System.out.println("ConcreteMethod B ... "+n);  
    8.         return n+10;  
    9.     }  
    10. }  

    2、拦截器

    定义一个拦截器。在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。

    Java代码  收藏代码
    1. public class ConcreteClassInterceptor implements MethodInterceptor{  
    2.     public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {  
    3.         System.out.println("Before:"+method);    
    4.         Object object=proxy.invokeSuper(obj, arg);  
    5.         System.out.println("After:"+method);   
    6.         return object;  
    7.     }  
    8. }  

    参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。

    返回:从代理实例的方法调用返回的值。

    其中,proxy.invokeSuper(obj,arg):

    调用代理类实例上的proxy方法的父类方法(即实体类ConcreteClassNoInterface中对应的方法)

    在这个示例中,只在调用被代理类方法前后各打印了一句话,当然实际编程中可以是其它复杂逻辑。

    3、生成动态代理类

    Java代码  收藏代码
    1. Enhancer enhancer=new Enhancer();  
    2. enhancer.setSuperclass(ConcreteClassNoInterface.class);  
    3. enhancer.setCallback(new ConcreteClassInterceptor());  
    4. ConcreteClassNoInterface ccni=(ConcreteClassNoInterface)enhancer.create();  

    这里Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展,以后会经常看到它。

    首先将被代理类ConcreteClassNoInterface设置成父类,然后设置拦截器ConcreteClassInterceptor,最后执行enhancer.create()动态生成一个代理类,并从Object强制转型成父类型ConcreteClassNoInterface。

    最后,在代理类上调用方法:

    Java代码  收藏代码
    1. ccni.getConcreteMethodA("shensy");  
    2. ccni.getConcreteMethodB(0);  

    查看控制台输出:

    控制台代码  收藏代码
    1. Before :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)  
    2. ConcreteMethod A ... shensy  
    3. After :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)  
    4. Before :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)  
    5. ConcreteMethod B ... 0  
    6. After :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)  

    可以看到,拦截器在调用被代理类方法前后都执行了print操作。

    转自:http://shensy.iteye.com/blog/1873155

  • 相关阅读:
    微信二维码 场景二维码 用于推送事件,关注等 注册用户 ,经过测试
    简单的 Helper 封装 -- CookieHelper
    简单的 Helper 封装 -- SecurityHelper 安全助手:封装加密算法(MD5、SHA、HMAC、DES、RSA)
    Java反射机制
    Windows Azure Web Site (13) Azure Web Site备份
    Windows Azure Virtual Machine (1) IaaS用户手册
    Windows Azure Web Site (1) 用户手册
    Windows Azure Web Site (12) Azure Web Site配置文件
    Windows Azure Web Site (11) 使用源代码管理器管理Azure Web Site
    Windows Azure Web Site (10) Web Site测试环境
  • 原文地址:https://www.cnblogs.com/wangzhongqiu/p/6672174.html
Copyright © 2011-2022 走看看