疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java 动态代理


 

Java 动态代理
 
1. 动态代理需要Proxy类
   
   动态代理一般使用java.lang.reflect.Proxy类的
   static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 
   方法创建一个代理类实例.
   
   传递的参数中:
     Class[] interfaces 表示可以把创建的代理类强制转换成相应的接口,然后调用接口方法.
     
     InvocationHandler 是一个接口.
     接口方法为invoke(Object proxy, Method method, Object[] args),
     
     Proxy.newProxyInstance方法创建接口类,需要一个这个接口的实现类.
     实现这个InvocationHandler接口的类时,需要在构造函数中,把被代理的 对象实例(target) 传递过去,
     然后在invoke方法中,调用Method method的method.invoke(target, args);方法(真正调用被代理实例的方法).
 
   总结:
   使用 Proxy.newProxyInstance 方法动态创建代理类实例.
      参数ClassLoader loader 类加载器,使用被代理类 实例的类加载器即可.
      
      参数 Class[] interfaces  决定 动态生成的代理实例可调用的方法(通过强制转化创建的代理类实例为该接口类型即可)
      
      代理类实例对Class[] interfaces中任何方法的调用,
      都转化成对InvocationHandler h参数(InvocationHandler接口的实现类)
      的invoke(Object proxy, Method method, Object[] args),方法的调用
      其中Object proxy 表示动态生成的代理类实例(即Proxy.newProxyInstance生成的实例);
      Method method 代理类实例调用的方法实例,
      
      在invoke方法中,调用Method method的method.invoke(target, args);方法,
      表示调用 被代理类实例(target)的 接口方法
      因为代理类实例调用接口方法时,其实是调用InvocationHandler的invoke方法,而在这个方法里面
      在调用Method method的method.invoke(target, args);方法(表示调用 被代理类的 接口方法) 的前后
      可以做一些额外操作,这样就实现了代理.
      
2. 相关代码
Java代码  
/** 
 *  
 * 被代理类实现的接口 
 * 
 */  
public interface TrainStack  
{  
  public void SaleTicket();  
}  
 
Java代码  
/** 
 *  
 * 被代理类 
 * 
 */  
public class TrainStackImpl implements TrainStack  
{  
  @Override  
  public void SaleTicket()  
  {  
    System.out.println("到达火车站售票处;");  
    System.out.println("给钱,买票");  
    System.out.println("");  
  }  
}  
 
Java代码  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
  
/** 
 *  
 * Proxy.newProxyInstance方法需要的参数: 
 * InvocationHandler接口实现类, 
 * 在这个类的构造函数中,传递被代理类的实例. 
 * Proxy.newProxyInstance创建的实例中调用的任何方法 
 * 都相当于调用InvocationHandler接口实现类的 
 * invoke方法,在invoke方法中调用 
 * method.invoke(target, args);表示被代理类实例的接口方法嗲用, 
 * 且在method.invoke(target, args)调用前后,可以做一些额外操作 
 * 这样就形成了动态代理 
 * 
 */  
public class TrainInvocationHandler implements InvocationHandler  
{  
  private Object target;  
    
  public TrainInvocationHandler(Object obj)   
  {  
   this.target = obj;  
  }  
  
  // 调用火车站买票的具体执行售票动作  
    
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   
  {  
   Object sales;  
   //代理先做一些初始工作  
   System.out.println("代理开始...");  
   System.out.println("买票人到达火车票代售点;");  
   System.out.println("先交代售票服务费;");  
   System.out.println("再交火车票票价钱;");  
   System.out.println("火车票代售点派人去火车站;");  
   System.out.println("");  
 
   //调用火车站售票的动作SaleTicket()方法  
   System.out.println("调用实际业务方法...");  
   sales = method.invoke(target, args);  
     
   //票买过后,代售点人买票回来  
   System.out.println("继续代理...");  
   System.out.println("火车票代售点人将代买来的火车票交给买票人.");  
     
   return sales;  
  }  
  
  // 火车票代售点,创建具体代理对象  
  // obj 接受具体买票的人  
  /** 
     * 这里要解释下面长长的代码的意思,以及具体做了哪些工作? 第一 
     * 根据obj.getClass().getClassLoader()这个要代理类的类加载器 
     * 和obj.getClass().getInterfaces()要代理类所实现的所有的接口 
     * 作为参数调用Proxy.getProxyClass(ClassLoader loader, Class... interfaces) 
     * 的方法返回代理类的java.lang.Class对象,也就是得到了java动态生成的代理类$Proxy0的Class对象。 
     * 同时,java还让这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了Proxy接口。 第二 
     * 实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h), 
     * 也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类 
     * 方法执行前后做额外工作的类TrainInvocationHandler。 
     * 这段代码Proxy.newProxyInstance(obj.getClass().getClassLoader(), 
     * obj.getClass().getInterfaces(), new TrainInvocationHandler(obj)) 
     * 得到的其实是一个类名叫$Proxy0 extends Proxy implements TrainStackImpl的类。 
     */  
  public static Object getInstance(Object obj)  
  {  
     
   return Proxy.newProxyInstance(  
     obj.getClass().getClassLoader(),  
     obj.getClass().getInterfaces(),  
     new TrainInvocationHandler(obj));  
  }  
  /** 
     * 大家如果还是不理解,可以看一下这段代码 
     *  
     * 创建某一接口 Foo 的代理: InvocationHandler handler = new MyInvocationHandler(...); 
     *  
     * Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new 
     * Class[] { Foo.class }); 
     *  
     * Foo f = (Foo) proxyClass.getConstructor( new Class[] { 
     * InvocationHandler.class }).newInstance(new Object[] { handler }); 
     *  
     * 或使用以下更简单的方法: Foo f = (Foo) 
     * Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { 
     * Foo.class }, handler); 
     */  
}  
   
 
Java代码  
/** 
 *  
 * 动态代理客户端调用测试 
 * 
 */  
public class TestDynamicProxy  
{  
  public static void main(String[] args)  
  {  
    TrainStack wantToBuy = new TrainStackImpl(); // 定义一个卖票的人  
    TrainStack buyTicket = (TrainStack) TrainInvocationHandler.getInstance(wantToBuy); // 类型要转换  
    buyTicket.SaleTicket(); // 调用卖票的方法,其实就是在调用invoke()这个方法  
  }  
}  
  
附,概念解释:
  什么叫代理呢,网络中有各种各样的代理,比如我们上网有时候用代理服务器。
    你通过这样上网就是使用了代理上网。
     再举个通俗的例子,你想找某局长帮你做一件事情,但局长官位显赫,你又不能轻易见着,你就想到了找他的秘书,通过她传话给局长,这样你就等于请他的秘书帮你办成了那件事。秘书为什么就可以找到局长呢,因为秘书和局长之间有一定的关系。这里产生了四个对象:你、秘书、局长、秘书-局长(关系)。 
      JAVA中同样有代理关系,我们叫做代理模式。
代理模式的作用是:为其他对象(局长)提供一种代理(秘书)以控制对这个对象(局长)的访问。代理对象可以在客户端(你)和目标对象(局长)之间起到中介的作用。
代理模式一般涉及到的角色有: 
1.抽象角色(秘书-局长):声明真实对象和代理对象的共同接口(秘书-局长)
2. 代理角色(秘书):代理对象角色(秘书)内部含有对真实对象(局长)的引用,从而可以操作真实对象(局长),同时代理对象(秘书)提供与真实对象(局长)相同的接口(秘书-局长)以便在任何时刻都能代替真实对象(局长)。同时,代理对象(秘书)可以在执行真实对象(局长)操作时,附加其他的操作,相当于对真实对象(局长)进行封装

3. 真实角色(局长):代理角色(秘书)所代表的真实对象(局长),是我们最终要引用的对象(局长)