Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1589516
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: Java

2017-05-17 22:43:09

在静态代理中,代理Proxy中的方法,都指定了调用了特定的realSubject中的对应的方法:

在上面的静态代理模式下,Proxy所做的事情,无非是调用在不同的request时,调用触发realSubject对应的方法;更抽象点看,Proxy所作的事情;在Java中 方法(Method)也是作为一个对象来看待了,

动态代理工作的基本模式就是将自己的方法功能的实现交给 InvocationHandler角色,外界对Proxy角色中的每一个方法的调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色的方法。如下图所示:



 在这种模式中,代理类Proxy和RealSubject都应该实现相同的功能,这里的功能可以理解为某个public方法
在面向对象的编程中,想让Proxy和RealSubject都实现相同的功能有两种方式:
a、一个比较直观的方式,就是定义一个功能接口,然后让Proxy和RealSubject都实现这个接口
b、比价隐晦的方式是通过继承。因为如果Proxy继承自RealSubject,这样Proxy则拥有了RealSubject的功能,Proxy还可通过重写RealSubject中方法来实现多态
时下比较流行的两种动态代理:JDK动态代理是以a思路设计,CGlib是以b思路设计的
JDK动态代理会做如下工作:1、获取RealSubject上所有接口,2、确定要生成的代理类的类名,默认为com.sun.proxy.$PrxoyXXX,3、根据需要实现的接口信息在代码中动态创建该Proxy类的字节码(byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());),4、将字节码转换成对应的class对象(所以需要传入classloader做参数),5、创建InvocationHandler实例对象,用来处理Proxy所有方法的调用,6、Prxoy的class对象以创建的handler对象为参数,实例化一个proxy对象
简单意思:Proxy类 根据要代理的对象的接口和InvocationHandler实例,先构造出代理类的字节码,然后通过传入的classloaer加载成class对象,然后在生成com.sun.proxy.$PrxoyXXX实例。要代理的对象的接口是让最后的实例和要代理的对象实现相同的功能,InvocationHandler实例是要增强的功能,
查看Proxy类的newProxyInstance方法

从生成对象方法中,我们看到三个关键的地方:
  • Class cl = getProxyClass0(loader, interfaces);//得到代理类
  • final Constructor cons = cl.getConstructor(constructorParams);   
  • newInstance(cons, ih);//将InvocationHandler h传入代理对象中,这点就有点像静态代理了,调用静态代理方法时,执行ih的invoke方法

结合下面的代码看

点击(此处)折叠或打开

  1. public interface Subject {
  2.     public void buy();
  3.     public void hello(String str);

  4. }

  5. *****************************
  6. public class RealSubject implements Subject {

  7.     /* (non-Javadoc)
  8.      * @see com.slg.aop.Subject#rent()
  9.      */
  10.     @Override
  11.     public void buy() {
  12.         System.out.println("I want buy something!");
  13.         
  14.         
  15.     }

  16.     /* (non-Javadoc)
  17.      * @see com.slg.aop.Subject#hello()
  18.      */
  19.     @Override
  20.     public void hello(String str) {
  21.         // TODO Auto-generated method stub
  22.         System.out.println("hello "+ str);
  23.         
  24.     }

  25. }
  26. *********************************
  27. public class DynamicProxy implements InvocationHandler {
  28.     
  29.     private Object subject;
  30.     /**
  31.      *
  32.      */
  33.     public DynamicProxy(Object object) {
  34.         // TODO Auto-generated constructor stub
  35.         this.subject= object;
  36.     }
  37.    
  38.     public Object getProxy(){
            return Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), this);
        }
  39.     /* (non-Javadoc)
  40.      * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
  41.      */
  42.     @Override
  43.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  44.         // TODO Auto-generated method stub
  45.         System.out.println("befroe method is invoke!");
  46.         System.out.println("method is "+method);
  47.         method.invoke(subject, args);
  48.         System.out.println("after method is invoke! ");
  49.         return this.subject;
  50.     }

  51. }
  52. *********************************
  53. public class TestAop {
  54.     
  55.      public static void main(String[] args)
  56.      {
  57.      // 我们要代理的真实对象
  58.      Subject realSubject = new RealSubject();

  59.      // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
  60.      InvocationHandler handler = new DynamicProxy(realSubject);

  61.      /*
  62.      * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
  63.      * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
  64.      * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
  65.      * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
  66.      */
  67.      Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
  68.      .getClass().getInterfaces(), handler);
  69.     
  70.      System.out.println(subject.getClass().getName());
  71.      subject.buy();
  72.      subject.hello("world");
  73.      }
  74.     

  75. }



Subject是被代理对象实现的接口,RealSubject是真正要被代理的对象类。在JDK实现的动态代理机制中动态代理类都要实现InvocationHandler接口,DynamicProxy就实现了这个接口,并且把要在被代理对象方法执行前(或执行后、)执行的逻辑写在invoke方法中。

下面重点看着这三段代码

Subject realSubject = new RealSubject();

这个是真正被代理的对象 

InvocationHandler handler = new DynamicProxy(realSubject);

这个是代理最终被代理的对象的代理类对象。(仔细理解) 

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject

                .getClass().getInterfaces(), handler);

这个subject是个代理类对象,它是在DynamicProxy对象上实现的代理

简单说就是 这个subject代理了DynamicProxy,DynamicProxy代理了 realsubject

看这个subject代理对象初始的方法的参数:

handler.getClass().getClassLoader() 使用同一个类加载器

realSubject.getClass().getInterfaces(),Proxy代理类所以要实现最终被代理类的所有接口中的方法

Handler,这个是关键,上一个参数告诉了代理对象要实现那些方法,怎么实现就是靠这个Handler了(通过组合的方式实现代理模式)。

具体我认为是 subject代理对象实现了realsubject中的所有方法,这个代理对象中有个成员变量是handler,在实现realsubject方法的时候调用将相应的参数传给handler,通过handler实现。

(具体传哪些参数 就看handlerinvoke方法了)

在往下说的话,可以看代码handler中实现代理的方式也是通过组合的方式,handler中有个最终被代理对象subject的对象(这个和上边那个subject不是同一个对象)。

所有动态代理的原理就是

Proxy代理类--代理了-->实现InvocationHandler接口的DynamicProxy--代理了-->最终被代理的对象

阅读(691) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~