JDK动态代理和CGLIB动态代理+源码下载

 在上一篇文章-java代理详解讲解实现机制,一种是继承另外一种是组合,而且通过做实现也证明使用组合的方式更加的灵活。之后提到了代理的两种种类,一种是静态代理,另外一种是动态代理。上一篇文件中着重介绍的是静态代理(相对于动态代理很容易理解)。这一片文章就接着介绍动态代理。

  动态代理实现的最终效果:通过以一个统一的方式实现对任意的接口/类的代理。相比较静态代理而言,我们可以不用再无限制的增加代理类,不用再写许多重复的代码。很符合面向对象设计原则中的"开闭原则":对修改关闭,对扩展开放。

  动态代理有很多的实现,我们比较熟悉的就是JDK动态代理和CGLIB的动态代理,这种两技术也是spring实现AOP的使用的重要技术。

1. JDK动态代理

    JDK底层封装了Proxy和InvocationHandler实现了对任意接口的代理。他们各自有自己的任务,Proxy主要负责动态生成代理类;InvocationHandler主要负责灵活指定代理内容。

1.1 动态生成代理类

   想要实现“通过一个统一的方式方式对任意接口的代理”,使用的方式就是将接口以参数的形式传递到创建代理类的方法中。在JDK中负责创建代理类的类就是Proxy,他提供了两个方法创建代理,分别是newProxyInstance()和getProxyClass()。下面是JDK帮助文档中对他们的介绍:

  

ProxyProxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。


关于Proxy的相关介绍


从帮助文档中可以看出JDK给我们提供了两种创建代理类的方式,代码如下
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.jdk.dynamicproxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Proxy;  
  5. import cn.jdk.dynamicproxy.Service;  
  6.   
  7. public class Main {  
  8.       
  9.     public static void main(String[] args) throws Throwable {  
  10. //      jdk动态代理==第一种创建方式--newProxyInstance()  
  11.         Object proxy = Proxy.newProxyInstance(  
  12.                 ServiceImpl.class.getClassLoader(),   
  13.                 ServiceImpl.class.getInterfaces(),   
  14.                 new ServiceInvocationHandler(new ServiceImpl()));  
  15.         Service service1 = (Service)proxy;  
  16.         service1.add();  
  17.           
  18.         //jdk和cglib两种动态代理都不能够代理final类型的方法  
  19.           
  20. //      jdk动态代理==第二种创建方式--getProxyClass()  
  21.         Class<?> proxyClass = Proxy.getProxyClass(  
  22.                 ServiceImpl.class.getClassLoader(),   
  23.                 ServiceImpl.class.getInterfaces());  
  24.           
  25.         Object serviceProxy = proxyClass.getConstructor(new Class[]{InvocationHandler.class})  
  26.               .newInstance(new ServiceInvocationHandler(new ServiceImpl()));  
  27.         Service service2 = (Service)serviceProxy;  
  28.         service2.add();  
  29.     }  
  30. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.jdk.dynamicproxy;  
  2.   
  3. public interface Service {  
  4.     public void add();  
  5. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.jdk.dynamicproxy;  
  2.   
  3. /** 
  4.  *    
  5. * 类名称:ServiceImpl    
  6. * 类描述: 委托类 
  7. * 修改人:pangfan     
  8. * 
  9.  */  
  10. public class ServiceImpl implements Service{  
  11.     public void add() {  
  12.         System.out.println("向数据库中添加数据!");  
  13.     }  
  14. }  

这是创建代理类的代码,但不是完整的还加上下面的灵活指定代理内容。

2.2 灵活指定代理内容

代理内容:在上一篇文章我们曾经介绍过"代理模式",那个里面提到代理类是需要对委托类进行预处理,过滤消息,把消息转发给委托类,以及事后处理消息。而这些预消息,过滤消息,把消息转发给委托类,以及事后处理消息就是代理内容。

比如对于事务代理而言,在执行委托类的方法之前,开启事务就是代理内容;方法执行之后,关闭事务也是代理内容。

灵活指定:由用户决定代理内容是什么!

下面就将代码补全,看一下执行效果。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.jdk.dynamicproxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5.   
  6. public class ServiceInvocationHandler implements InvocationHandler {  
  7.     private Object obj;  
  8.     public ServiceInvocationHandler(Service service) {  
  9.         super();  
  10.         this.obj = service;  
  11.     }  
  12.     public Object invoke(Object proxy, Method method, Object[] args)  
  13.             throws Throwable {  
  14.          Object result=null;    
  15.         System.out.println("jdk动态代理--开始事务");  
  16.         result = method.invoke(obj,args);  
  17.         System.out.println("jdk动态代理--结束事务 "+"\r\n");  
  18.         return result;  
  19.     }  
  20. }  

执行效果展示:



最后用一张UML图将上面的所有东西做一个总结。



2. CGLIB动态代理

上面的指能够动态生成接口的代理类,如果是一个类就不能够动态生成。而cglib能够动态生成类的代理类,这个类可以不用实现接口

实现原理基本上是一样的,应用也是基本上一样的。

需要引用的jar包:cglib-nodep-2.2.2.jar 和 com.springsource.org.objectweb.asm-3.2.0.jar

直接上代码:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.cglib.dynamicproxy;  
  2.   
  3. import net.sf.cglib.proxy.Enhancer;  
  4.   
  5. public class Main {  
  6.   
  7.     public static void main(String[] args) {  
  8. //      cglib动态代理  
  9.         Monkey monkey = (Monkey)Enhancer.create(  
  10.                 Monkey.class,  
  11.                 new MonkeyInvocationHandler());  
  12.         monkey.eat();  
  13. //      final方法不能够被代理  
  14.         monkey.type();  
  15.     }  
  16. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.cglib.dynamicproxy;  
  2.   
  3. public class Monkey {  
  4.       
  5.     public void eat(){  
  6.         System.out.println("吃香蕉!");  
  7.     }  
  8.     //final方法,测试是否能够代理此方法  
  9.     public final String type(){  
  10.         return "金丝猴";  
  11.     }  
  12. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package cn.cglib.dynamicproxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.MethodInterceptor;  
  6. import net.sf.cglib.proxy.MethodProxy;  
  7.   
  8. public class MonkeyInvocationHandler  
  9.         implements MethodInterceptor {  
  10.     public Object intercept(Object proxy, Method method, Object[] args,  
  11.             MethodProxy methodProxy) throws Throwable {  
  12.          Object result=null;    
  13.         System.out.println("cglib动态代理--开始事务");  
  14.         result = methodProxy.invokeSuper(proxy,args);  
  15.         System.out.println("cglib动态代理--结束事务");  
  16.         return result;  
  17.     }  
  18. }  

源码下载地址:jdk和cglib实现动态代理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值