zoukankan      html  css  js  c++  java
  • CGLib与JDK的动态代理

    一、CGLib 简单介绍

            CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库。

    它能够在执行期扩展Java类与实现Java接口。

    Hibernate用它来实现PO字节码的动态生成。CGLib比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅能够接管接口类的方法。还能够接管普通类的方法

              CGLib 的底层是Java字节码操作框架 —— ASM。

    CGLib就是封装了ASM,简化了ASM的操作,实现了在执行期动态生成新的class。ASM是直接生成class类的方式。不会有性能问题(相对来说)

    二、JDK的动态代理 (VS) CGLib

    1、实现原理

    JDK的动态代理——依据java的反射机制动态生成

             利用反射。获取托付类的类载入器。托付类的全部接口,实例化代理类。

    通过反射类Proxy以及InvationHandler回调接口实现的。可是动态代理类仅仅能对该类所实现的接口中的方法进行代理。

    具有一定的局限性,而且反射的效率也不是非常高。

              Proxy 毕竟是通过反射实现的,必须在效率上付出代价:有实验数据表明,调用反射比一般的函数开销至少要大 10 倍。

    从程序实现上能够看出,对 proxyclass 的全部方法调用都要通过使用反射的 invoke 方法。

    因此。对于性能关键的应用。使用 proxy class是须要精心考虑的。以避免反射成为整个应用的瓶颈。

    CGLib ——利用ASM生成字节码原理。利用增强类,创建代理类

           CGLib底层採用ASM字节码生成框架。使用字节码技术生成代理类。比反射效率要高。

    可是须要主要注意的,CGLib不能对声明为final的方法进行代理。

    由于CGLib原理是动态的生成被代理类的子类。

            ASM可以通过改造既有类,直接生成须要的代码。

    增强的代码是硬编码在新生成的类文件内部的,没有反射带来性能上的付出。它是一个普通的 Java 类而不是 proxy类,甚至可以在应用程序的类框架中拥有自己的位置,派生自己的子类。

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

    2、代码实现

    JDK动态代理

    package DynamicProxy2upgrade;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /** 
     * @ClassName: DynamicProxy 
     * @Description: 动态代理类。在这里做了一个升级。把代理绑定真实类的关系。Proxy生成实例的代码移到了动态代理这里 
     * @author 张薄- huaxiangniaoyu0109@126.com
     * @date 2015年5月29日 下午9:21:19 
     */
    public class DynamicProxy implements InvocationHandler {
    
    	private Object obj ;  //托付类,真实类
    	
    	DynamicProxy(Object obj){
    		this.obj=obj;
    	}
    	
    	//绑定代理与托付类。生成新的代理类
    	public Object bindProxy(Object obj){
    		
    		//返回一个指定接口的代理类实例,该接口能够将方法调用指派到指定的调用处理程序,如ProxyHandler
    		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    	}
    	
    	
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {		
    		return method.invoke(obj, args); //普通的java反射代码,通过反射运行某个类的方法(invoke方法内部实现预处理,对托付类方法调用,事后处理等逻辑。)
    	}
    
    }
    


    JDK动态代理执行结果:‘

                             


    CGLib动态代理

     

    package CGLibDynamicProxy;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer; //一个字节码增强类,它能够方便的对你想要处理的类进行扩展
    import net.sf.cglib.proxy.MethodInterceptor; //方法拦截器
    import net.sf.cglib.proxy.MethodProxy; //代理类。JDK的java.long.reflect.Method类的代理类,能够方便的实现对源对象方法的调用(如invokeSuper)
    /** 
     * @ClassName: DynamicProxybyCGLib 
     * @Description: 基于CGLib的动态代理
     * @author 张薄- huaxiangniaoyu0109@126.com
     * @date 2015年5月31日 上午8:44:19 
     */
    public class DynamicProxybyCGLib implements MethodInterceptor {
    	
    	private Object obj;  //托付类
    	public Object getInstance(Object obj){
    		this.obj = obj;
    		Enhancer enhancer = new Enhancer();  //增强类
    		//不同于JDK的动态代理。它不能在创建代理时传obj对 象,obj对象必须被CGLIB包来创建
    		enhancer.setSuperclass(this.obj.getClass()); //设置被代理类字节码(obj将被代理类设置成父类;作为产生的代理的父类传进来的)。CGLIB依据字节码生成被代理类的子类		
    		enhancer.setCallback(this);	//设置回调函数,即一个方法拦截
    		return enhancer.create(); //创建代理类
    	}
    
    	@Override
    	public Object intercept(Object obj, Method method, Object[] args,
    			MethodProxy methodProxy) throws Throwable {
    		System.out.println("obj:" + obj.getClass().getName());  //由CGLib动态生成的代理类实例
    		System.out.println("method:" + method.getName());	//上文中实体类所调用的被代理的方法引用
    		System.out.println("methodProxy:" + methodProxy.getClass().getName()); //生成的代理类对方法的代理引用
    		System.out.println("args:"+ args); //參数值列表
    		
    		Object object = methodProxy.invokeSuper(obj, args);  //调用代理类实例上的methodProxy方法的父类方法(即实体类RealSubject中的相应方法)
    		
    		return object;
    	}
    
    }
    


    CGLib动态代理执行结果:

                             

    三、小结

             CGLib实现的原理,非常详细的原理可能我还是不太懂。可是,大概知道一个过程,首先依据Enhancer创建代理类,怎样创建的呢?依据方法setSuperclass将被代理类作为父类引入。再依据CGLib生成被代理类的子类。依据方法setCallback,回调函数(这里我们的动态代理类实现MethodInterceptor拦截器,依据拦截器的方法intercept,调用代理类的父类方法。实现了代理被代理类的方法的目的),实现方法拦截。最后用create方法创建代理类。

             既然口述了CGLib的实现原理,那就再来说说JDK的动态代理吧。依据Proxy的方法newProxyInstance方法创建代理类。该方法里面的參数,分别获取了被代理类的类载入器(用于动态载入),被代理类的全部接口类(以便于实现接口类的全部方法),再通过动态代理类实现InvationHandler。实现接口方法invoke。回调函数(通过反射运行被代理类的方法),这样在实例化动态代理类的时候,就真正的创建了动态代理。

             啰里啰嗦的说了这么多,收获还是有的。说出我的心得,假设大家有不同的想法,欢迎拍砖哈。

    比方,CGLib的动态代理类。原理是继承,生成了被代理类的子类;而JDK的动态代理类。原理是反射,生成的代理类。实际不具备被代理类内部的方法,每一次调用都须要利用反射。调用被代理类的方法;再来看静态代理,代理类就是通过调用被代理类的方法进行执行的,而它自己本身并不详细被代理类的方法,JDK的动态代理的进步在于。利用反射,将类的载入延迟到程序执行中,解耦了代理类与被代理的关系。

  • 相关阅读:
    助力APP尽情“撒币”!阿里云正式上线移动直播问答解决方案
    Linux API的fork()测试
    完美搞定《DOCKER IN ACTION》第二章示例
    docker+python无头浏览器爬虫
    阿里云播放器SDK的正确打开方式 | Aliplayer Web播放器介绍及功能实现(三)
    11月9日云栖精选夜读:阿里90后工程师_如何用AI程序写出双11打call歌?
    知名网站的 404 页面长啥样?你的404长啥样?
    10月24日云栖精选夜读:2017杭州•云栖大会完美收官 虚拟化平台精彩回顾
    memcache漏洞你补上了吗
    5分钟用Jitpack发布开源库
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5316693.html
Copyright © 2011-2022 走看看