您的位置:首页 > 编程语言 > Java开发

从原理出发理解JDK动态代理

2014-04-08 00:01 253 查看
一、从静态代理出发

要理解动态代理的原理,首先我们来分析一下静态代理的两种实现方法:

比如说,我有一个Tank类和一个Moveable接口,接口中有一个move的方法,而Tank类实现了这一接口,当我们在交付了代码之后,即原来的代码不能修改了,我们想要在Tank类的那个move()方法中添加日志的逻辑或者时间的计算等等业务逻辑时,我们怎么办?

   


   


两种方式:

(1)使用继承的方式实现静态代理;

     在这种方式下,我们可以写一个类Tank2,这个类继承Tank类,然后重写move()方法。

  增加业务逻辑。

(2)使用聚合的方式实现静态代理;

    在这种方式下,我们可以写一个类TankProxy,这个类实现了Moveable接口,然后聚合了Tank作为成员变量,最后实现方法    move(),在其中增加需要的业务逻辑。

那么在静态代理的设计模式中,使用聚合实现还是继承实现会比较好?

答案是采用聚合的方式实现静态代理比较好,原因很简单,我们设想一下,如果我们首先需要添加日志的业务逻辑,这个时候我们采用继承的方式来实现,我们需要建一个新的类Tank1,然后又来了一个业务逻辑,比如效率检查,我们又建一个类Tank2,而当我们需要将各个业务逻辑进行不知道顺序的组合时,每一次我们都要建一个新的类,是不是相当麻烦。我们再看看采用聚合的方式,虽然说每来一个业务逻辑,同样需要建一个类,但当我们需要将业务逻辑不明顺序的组合时,我们不需要建新的类,只需要在客户类中进行设置就可以了;而且我们在设计模式中提到过的面向对象设计原则中,合成复用原则就是提倡我们多用关联,少用继承。(虽然说有点难理解,但是仔细去琢磨,道理就是这样)

 

二、从原理进入JDK动态代理

  首先,我们需要明白为什么会有动态代理,因为静态代理太死了,我们需要对每一个需要代理的目标编写代理类,而动态代理的Proxy可以对任意对象产生代理(不用看到代理类的名字)。

  关于JDK动态代理,最最主要和核心的是java.lang.reflect.Proxy这个类和InvocationHandler这个接口。

  Proxy类中核心的方法是:

   


  InvocationHandler的核心方法是:

   


    

   好了,谈完了JDK动态代理的核心之后,我们来分析动态代理的原理:

  (1)首先,我们创建一个Proxy类,用这个类来模拟JDK的Proxy类;

     


    编写其最核心的方法,即产生代理类的方法,其中两个参数,一个传递被代理对象所实现的接口,一个是InvocationHandler对象;

  在这个方法中我们主要有以下四个步骤来产生代理类:

    1.第一步,我们需要动态的将代理类的内容写入一个指定目录下的文件名为$Proxy1(JDK动态代理生成的代理类名字就是这种形式):

     


     


     


  生成文件:

     


   

  2.第二步,将该代理类文件进行编译,生成.class文件:

     


   生成目录:

     


   3.第三步,将类加载到内存中,这里采用URLClassLoader,实际中我们也可以采用从客户端传过来的与被代理类相对应的ClassLoader:

      


   4.第四步,创建代理对象的实例,学过Java反射原理的应该知道,如果一个类没有无参构造函数,那么不能调用newInstance()方法来实现创建实例;而我么所讲的例子中的代理类中是有参构造函数,看看生成的代理文件吧:

     


  从而采用构造器来生成实例:

     


    这就是我们Proxy类中实际会进行的这些操作。

(2)而关于InvocationHandler类,我们只有一个方法:

     


我们需要任何的业务逻辑,我们都将创建一个类并实现InvocationHandler;例如一个TimeHandler:

           


           


         

  (3)客户端:

      


    总而言之,我们首先通过Proxy类产生代理对象,在客户端获得代理对象之后,调用代理后的方法,而在这个方法中我们将会调用InvocationHandler对象的invoke()方法,从而实现业务的添加,即代理。

      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: