下面我们来个一个静态代理的实现。 
我以一个坦克为例。

 
抽象主题角色:Moveable 

[java] view plaincopy

  1. package com.gjy.proxy;  

  2.   

  3.     public interface Moveable {  

  4.     void move();  

  5. }  

代理主题角色:TanktimeProxy 

[java] view plaincopy

  1. package com.gjy.proxy;  

  2.   

  3. public class TanktimeProxy implements Moveable{  

  4.         private Moveable t;  

  5.       

  6.         public TanktimeProxy(Moveable t) {  

  7.             super();  

  8.             this.t = t;  

  9.         }  

  10.   

  11.   

  12.         @Override  

  13.         public void move() {  

  14.             long time1 = System.currentTimeMillis();  

  15.             System.out.println("time1="+time1);  

  16.             t.move();  

  17.             long time2 = System.currentTimeMillis();  

  18.             System.out.println("time2="+time2);  

  19.             System.out.println("运行时间为:"+(time2-time1));  

  20.         }  

  21. }  


实际被代理对象:Tank 

[java] view plaincopy

  1. package com.gjy.proxy;  

  2.   

  3. public class Tank implements Moveable{  

  4.   

  5.         @Override  

  6.         public void move() {  

  7.             System.out.println("TanK moving........");  

  8.         }  

  9.       

  10. }  

测试:

[java] view plaincopy

  1. package com.gjy.proxy;  

  2.   

  3. public class TestTank {  

  4.         public static void main(String[] args) {  

  5.             Tank t = new Tank();  

  6.             Moveable move = new TanktimeProxy(t);  

  7.             move.move();  

  8.           

  9.         }  

  10. }  

 

上述为静态代理,动态代理是在静态代理基础上发展的

有静态代理可知,需要,

  1. 一个接口Moveable

  2. 被代理类,实现该接口

  3. 代理类也要实现该接口。

  4. 创建被代理类实例对象,和代理对象,并把被代理对象传递给代理对象。

  5. 调用代理对象的实现接口中的方法。

 

动态代理:

在程序运行时,创建类(该类在程序未运行时,不存在)的定义,并生成该类的实例对象。

1

Main(){

         Tank t=new Tank();           //创建被代理类

         InvocationHandler h=new  TimeHandler(t);   //创建逻辑功能,即切面

         //Proxy的静态方法newProxyInstance返回代理类

         Moveable m=( Moveable)Proxy.newProxyInstance(Moveable.class, h);

        

         m.move();

 

}

 

2//该方法不能直接通过实例对象调用invoke()方法,因为不知道切入点,即在哪些方法执行之前或之后执行切面。该方法是为代理对象调用的。

Class TimeHandler  implements  InvocationHandler{

     Object target;     //该对象用于保存被代理对象

     TimeHandler(Object target){

         This.target=target;

    }

     invoke(Object proxy,Method m){proxy对象一般没有什么用处,如果使用method.invoke(proxy, args);会造成死循环

    /*业务逻辑,切面*/

     System.out.println(“时间1”);

     m.invoke(target);    //注意该invoke方法为Method对象的静态方法(jDK的)

     System.out.println(“时间1”);

 

 

}

 

}

 

3

Interface InvocationHandler{

    Invoke(Object o,Method m);

 

}

 

 

 

4

Class  Proxy{           

    Static  newProxyInstance(Class infce, InvocationHandler h){

                  

       1.根据反射,获取接口infce中的方法名,

       2.创建infce的代理类的定义

       3.创建代理类的实例对象,并把h参数传递给代理实例对象

       4.返回代理对象

    }

}

具体实现:

Static  newProxyInstance(Class infce, InvocationHandler h){

String str=””;

遍历infce,获取方法名,如move

Str=”

         Class  TankTimeProxy implements “+infce.getName+”

         {

                   InvocationHandler  h;

                   TankTimeProxy(InvocationHandler h){  //创建构造方法

         this.h=h;

}”+

move+”(){

         h.invoke(this,”+Method1+”)

 

}

}


str写入一个TankTimeProxy.java文件中,编译并加载该类                  

根据反射创建该类实例。CTankTimeProxy类的字节码

Constructor  ctr=c.getConstructor(InvocationHandler.class);

//得到参数为InvocationHandler类型的构造函数

Object m=ctr.newInstance(h);        

//创建TankTimeProxy的一个实例对象,并传入h参数

                   return m;

}

 

 

 

 其实:动态创建的代理类不具有任何逻辑,在实现接口方法中:

move(){

    h.invoke(this,"move");


}

由于h中并没有使用this对象,而是target故实现代理功能。


 

 

 

分析:

Main(){

         Tank t=new Tank();           //创建被代理类

         InvocationHandler h=new  TimeHandler(t);   //创建逻辑功能,即切面

         //Proxy的静态方法newProxyInstance返回代理类

         Moveable m=(Moveable)Proxy.newProxyInstance(Moveable.class,h);       

         m.move();

}

代理_代理




总结:相当于TimeHandler代理TankTankTimeProxy又代理TimeHandler

  1. 当调用TankTimeProxy对象的move,调用TimeHandlermove ,

  2.  TimeHandler调用Tankmove

  3. 和静态代理唯一不同的是TankTimeProxy是动态生成。

 

 

 

 

 

 

疑惑:为什么不直接把TimeHandler代理,不用再包装一道。

答:

(1)因为你会发现TimeHandler中不会出现被代理对象的方法名称,使用动态代理完全分离了TimeHandler与被代理对象的分离。任何需要该切片功能的对象都可以给TimeHandler代理。

静态代理则必须修改代理类源代码(硬编码了被代理对象的方法名),其实静态代理可以使用方法注入,实现分离。

(2)使用动态代理,只需要编写切片逻辑过程,代理类由JVM生成,可以直接调用Java API,不用单独写一个代理类。一个切面类,可以被多个类使用,代理类有JVM生成。

 

 

动态代理例子:

import java.util.*;

 

 

publicclass TestMain {

 

    /**

     * @param args

     */

    publicstaticvoid main(String[] args) {

 

        ArrayList target=newArrayList();

       

        ProxyFactory proxyFactory=new ProxyFactory();

        proxyFactory.setTarget(target);

        Collection proxy=(Collection)proxyFactory.getProxy();

        proxy.add("one");

        System.out.println("--------------------间隔符--------------------------"); 

        System.out.println(proxy.toString());//代理调用方法一次 

       

 

    }

 

}

 

/////////////////////////////////////////////////////////////////

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

 

 

publicclass ProxyFactory implements InvocationHandler {

 

    private Object target;

   

     

    publicvoid setTarget(Object target) {

        this.target = target;

    }

//该方法也可以在main()函数中

//this对象换成ProxyFactory实例对象

    public Object getProxy(){

        if(target==null){

            System.out.println("未设置目标类");

            returnnull;

        }

Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),

                                            target.getClass().getInterfaces(), this);

        return proxy;

    }

   

    @Override

    public Object invoke(Object proxy, Method method, Object[] args)//proxy对象一般没有什么用处,如果使用method.invoke(proxy, args);会造成死循环,

                                                                    //    因为proxy执行该方法使用的是ProxyFactory 中的invoke()方法

            throws Throwable {

 

        System.out.println("调用方法前");

        Object returnValue=method.invoke(target, args);

       

        System.out.println("调用方法后");

   

        return returnValue;

    }

    //////////////////////////////////

运行结果:

调用方法前

调用方法后

--------------------间隔符--------------------------

调用方法前

调用方法后

[one]