Java动态代理的之JDK和CGLIB

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。 在Java中主要可以分为JDK和CGLIB的方法实现。

下面来看看一些实例吧!

一、JDK方式

1、接口类

[java]  view plain  copy
  1. package com.func.axc.proxy;  
  2.   
  3. /** 
  4.  * 功能概要: 
  5.  *  
  6.  * @author linbingwen 
  7.  * @since  2016年6月2日  
  8.  */  
  9. public interface  Book {  
  10.     public void addBook();    
  11.   
  12. }  

2、实现类

[java]  view plain  copy
  1. package com.func.axc.proxy;  
  2.   
  3. /** 
  4.  * 功能概要: 
  5.  *  
  6.  * @author linbingwen 
  7.  * @since  2016年6月2日  
  8.  */  
  9. public class BookJdk implements Book {  
  10.   
  11.     @Override  
  12.     public void addBook() {  
  13.         System.out.println("添加一本新书");  
  14.           
  15.     }  
  16.   
  17. }  
3、代理类

[java]  view plain  copy
  1. package com.func.axc.proxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.lang.reflect.Proxy;  
  6.   
  7. /** 
  8.  * 功能概要: 
  9.  *  
  10.  * @author linbingwen 
  11.  * @since  2016年6月2日  
  12.  */  
  13. public class BookProxyJdk implements InvocationHandler  {  
  14.       
  15.        private Object target;    
  16.         /**  
  17.          * 绑定委托对象并返回一个代理类  
  18.          * @param target  
  19.          * @return  
  20.          */    
  21.         public Object bind(Object target) {    
  22.             this.target = target;    
  23.             //取得代理对象    
  24.             return Proxy.newProxyInstance(target.getClass().getClassLoader(),    
  25.                     target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)    
  26.         }   
  27.   
  28.     @Override  
  29.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  30.         Object result=null;    
  31.         System.out.println("jdk实现的前置代理");    
  32.         //执行方法    
  33.         result=method.invoke(target, args);    
  34.         System.out.println("jdk实现的前置代理");    
  35.         return result;   
  36.     }  
  37.   
  38. }  

4、测试

[java]  view plain  copy
  1. BookProxyJdk proxy = new BookProxyJdk();    
  2.       Book book = (Book) proxy.bind(new BookJdk());    
  3.       book.addBook();    
结果:

jdk实现的前置代理
添加一本新书
jdk实现的前置代理


二、CGLIB动态代理

1、无继承的类

[java]  view plain  copy
  1. package com.func.axc.proxy;  
  2.   
  3. /** 
  4.  * 功能概要: 
  5.  *  
  6.  * @author linbingwen 
  7.  * @since  2016年6月2日  
  8.  */  
  9. public class BookCglib {  
  10.       
  11.     public void addBook() {  
  12.         System.out.println("添加一本新书");  
  13.           
  14.     }  
  15.   
  16. }  
2、代理类

[java]  view plain  copy
  1. package com.func.axc.proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import org.springframework.cglib.proxy.Enhancer;  
  6. import org.springframework.cglib.proxy.MethodInterceptor;  
  7. import org.springframework.cglib.proxy.MethodProxy;  
  8.   
  9. /** 
  10.  * 功能概要: 
  11.  *  
  12.  * @author linbingwen 
  13.  * @since  2016年6月2日  
  14.  */  
  15. public class BookProxyCglib implements MethodInterceptor {  
  16.       
  17.     private Object target;    
  18.         
  19.     /**  
  20.      * 创建代理对象  
  21.      *   
  22.      * @param target  
  23.      * @return  
  24.      */    
  25.     public Object getInstance(Object target) {    
  26.         this.target = target;    
  27.         Enhancer enhancer = new Enhancer();    
  28.         enhancer.setSuperclass(this.target.getClass());    
  29.         // 回调方法    
  30.         enhancer.setCallback(this);    
  31.         // 创建代理对象    
  32.         return enhancer.create();    
  33.     }    
  34.       
  35.   
  36.     @Override  
  37.     public Object intercept(Object arg0, Method arg1, Object[] arg2,  
  38.             MethodProxy arg3) throws Throwable {  
  39.            System.out.println("cglib实现的前置代理");  
  40.               
  41.             //通过代理类调用父类中的方法  
  42.             Object result = arg3.invokeSuper(arg0, arg2);  
  43.               
  44.             System.out.println("cglib实现的后置代理");  
  45.             return result;  
  46.     }  
  47.   
  48. }  

3、测试

[java]  view plain  copy
  1. BookProxyCglib cglib=new BookProxyCglib();    
  2. BookCglib bookCglib=(BookCglib)cglib.getInstance(new BookCglib());    
  3. bookCglib.addBook();    
输出结果:

cglib实现的前置代理
添加一本新书
cglib实现的后置代理



三、JDK动态代理和CGLIB字节码生成的区别? 

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理和CGLib的性能比较
CGLib所创建的动态代理对象的性能比JDK所创建的代理对象性能高不少,大概10倍,但CGLib在创建代理对象时所花费的时间却比JDK动态代理多大概8倍,所以对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建新的实例,所以比较适合CGLib动态代理技术,反之则适用于JDK动态代理技术。另外,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行处理。所以,大家需要根据实际的情况选择使用什么样的代理了。

同样的,Spring的AOP编程中相关的ProxyFactory代理工厂内部就是使用JDK动态代理或CGLib动态代理的,通过动态代理,将增强(advice)应用到目标类中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值