JAVA代理学习

自己在看JAVA 核心技术那本书,然后在看到代理的时候有些困惑,没看懂,在网上找了一些例子,仅供参考。

感谢:

原博客地址:               http://gongjiayun.iteye.com/blog/948778

动态代理的例子:          http://hi.baidu.com/malecu/item/9e0edc115cb597a1feded5a0

Java动态代理模式 
1. 代理:一个角色代表别一个角色来完成某些特定的功能。 
比如:生产商,中间商,客户这三者这间的关系 
客户买产品并不直接与生产商打交道,也不用知道产品是如何产生的,客户只与中间商打交道,而中间商就可以对产品进行一些包装,提供一些售后的服务。 

代理模式有三个角色: 1. 抽象主题角色 2. 代理主题角色 3. 实际被代理角色 
其它类通过访问代理主题角色来访问实际被代理角色。 

2. 下面我们来个一个静态代理的实现。 
我以一个坦克为例。 
抽象主题角色:Moveable 

Java代码  收藏代码
  1.   package com.gjy.proxy;  
  2.   
  3. blic interface Moveable {  
  4. void move();  

代理主题角色:TanktimeProxy 
Java代码  收藏代码
  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代码  收藏代码
  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代码  收藏代码
  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. }  

从上例可以看到代理主题角色:TanktimeProxy实现了对Tank的move()方法运行时间的计算,而TanktimeProxy,Tank都实现了Moveable接口,通过调用TanktimeProxy的move()方法我们可以实现对Tank的move()方法的运行时间的计算,而不用在Tank的move()方法中作任何实现,这就是代理的作用。代理实现时TanktimeProxy,Tank必需实现Moveable接口。 

下面我想在TanK的move()方法前后加上日志: 
我必需再写一个类来实现这一功能: 
Java代码  收藏代码
  1. package com.gjy.proxy;  
  2.   
  3. public class TanklogProxy implements Moveable{  
  4.         private Moveable t;  
  5.       
  6.         public TanklogProxy(Moveable t) {  
  7.             super();  
  8.             this.t = t;  
  9.         }  
  10.   
  11.   
  12.         @Override  
  13.         public void move() {  
  14.             System.out.println("start move........");  
  15.             t.move();  
  16.             System.out.println("end move......");  
  17.         }  
  18. }  

测试: 
Java代码  收藏代码
  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.             Moveable movet = new TanklogProxy(move);  
  8.             movet.move();  
  9.           
  10.         }  
  11. }  

这样我通过代理在Tank的move()方法前后加入了日志和时间统计的功能,由于TanktimeProxy,TanklogProxy都实现了Moveable接口,所以TanklogProxy可以代理TanktimeProxy,反过来也可以,它们对Tank的代理顺序是可以交换的。 

如果我想在Tank的move()方法调用的前后加入更多的功能,是不是要写更多的代理主题角色,这样子会使得代码过于臃肿,不易于维护,那有没有什么办法可以解决呢,答案是可以的,我们可以动态的来生成代理主题角色,来代理所有的被代理对象,这就是动态代理。 

下面是一个简单的动态代理的实现: 
类图如下: 
JAVA代理学习_第1张图片 

首先编写一个生成代理主题角色的类:Proxy 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileWriter;  
  5. import java.lang.reflect.Constructor;  
  6. import java.lang.reflect.Method;  
  7. import java.net.URL;  
  8. import java.net.URLClassLoader;  
  9.   
  10. import javax.tools.JavaCompiler;  
  11. import javax.tools.StandardJavaFileManager;  
  12. import javax.tools.ToolProvider;  
  13. import javax.tools.JavaCompiler.CompilationTask;  
  14.   
  15. public class Proxy {  
  16. public static Object newProxyIntenct(Class infac,InvocationHandler h) throws Exception{  
  17.             String br ="\r\n";  
  18.           
  19.             String methString ="";  
  20.             Method[] method = infac.getMethods();  
  21.           
  22.             for(Method m: method){  
  23.                 methString = "  @Override"+ br +  
  24.                     "   public void "+m.getName()+"() {"+ br +  
  25.                     "       try {" + br +  
  26.             "       Method md ="+ infac.getName()+".class.getMethod(\""+m.getName()+"\");"+ br +  
  27.                         "       h.invoke(this,md);" + br +  
  28.                     "       }catch (Exception e){ "+ br+   
  29.                         "           e.printStackTrace();" + br +   
  30.                         "       }" + br +  
  31.                     "   }";  
  32.             }  
  33.           
  34.             String src =   
  35.                     "package com.gjy.DynamicProxy;" + br +  
  36.                     "import java.lang.reflect.Method;" + br +  
  37. "public class $Proxy implements "+infac.getName()+"{" + br +  
  38. "   private com.gjy.DynamicProxy.InvocationHandler h;" + br +  
  39.                 "   public $Proxy(InvocationHandler h) {" + br +  
  40.                 "       super();" + br +  
  41.                 "       this.h = h;" + br +  
  42.                 "   }" + br + br +  
  43.                 methString +br +  
  44.                 "}";  
  45.                 MakFileUtil.createFile("D:/src/com/gjy/DynamicProxy");  
  46.                 //生成java文件  
  47. String fileName ="D:\\src\\com\\gjy\\DynamicProxy\\$Proxy.java";  
  48.                 System.out.println(fileName);  
  49.                 File file = new File(fileName);  
  50.                 FileWriter fWriter = new FileWriter(file);  
  51.                 fWriter.write(src);  
  52.                 fWriter.flush();  
  53.                 fWriter.close();  
  54.               
  55.                 //生成class文件,jdk6提供的工具类  
  56. JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();  
  57.                 //System.out.println(compiler.getClass().getName());  
  58. StandardJavaFileManager fileManager = compiler.getStandardFileManager(nullnullnull);  
  59. Iterable units = fileManager.getJavaFileObjects(fileName);  
  60. CompilationTask task = compiler.getTask(null, fileManager, nullnullnull, units);  
  61.                 task.call();  
  62.                 fileManager.close();  
  63.               
  64.                 //装载到内存,生成新对象  
  65.                 URL[] urls = new URL[]{new URL("file:/"+"D:\\src\\")};  
  66.                 URLClassLoader loader = new URLClassLoader(urls);  
  67. Class c = loader.loadClass("com.gjy.DynamicProxy.$Proxy");  
  68.               
  69.                 //通过有参的构造器反射生成代理类的实例  
  70. Constructor ctr = c.getConstructor(InvocationHandler.class);  
  71.                 Object obj = (Object) ctr.newInstance(h);   
  72.                 return obj;  
  73.         }  
  74. }  


代理对象的操作接口: 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. public interface InvocationHandler {  
  6.         void invoke(Object o,Method m);  
  7. }  

通过实现代理对象的操作接口实现对被代理对象的方法调用前后的逻辑操作。 

TimeInvocationHandler实现InvocationHandler接口: 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5.   
  6. public class TimeInvocationHandler implements InvocationHandler {  
  7.         private Object target;  
  8.         public TimeInvocationHandler(Object target) {  
  9.             super();  
  10.             this.target = target;  
  11.         }  
  12.         @Override  
  13.         public void invoke(Object o, Method m) {  
  14.             long time1 = System.currentTimeMillis();  
  15.             System.out.println("time1="+time1);  
  16.          try {  
  17.                 m.invoke(target);  
  18.             } catch (Exception e) {  
  19.                 e.printStackTrace();  
  20.             }  
  21.             long time2 = System.currentTimeMillis();  
  22.             System.out.println("time2="+time2);  
  23.             System.out.println("Tank 的启动时间:"+(time2-time1));  
  24.         }  
  25.   
  26. }  


实际被代理对象:Tank 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. ublic class Tank implements Moveable{  
  4.   
  5.     @Override  
  6.     public void move() {  
  7.         int a = 5;  
  8.         int b = 6;  
  9.         int c = 0;  
  10.         int d = 0;  
  11.         for (int i = 0; i < 1000; i++) {  
  12.             d = i;  
  13.         }  
  14.         c = ((a+b)/2)*12;  
  15.         System.out.println("TanK moving..Tank 的速度是"+c);  
  16.       
  17.     }  

抽象代理主题:Moveable 
Java代码  收藏代码
  1.     package com.gjy.DynamicProxy;  
  2. public interface Moveable {  
  3.             void move();  
  4. }  
  5. }  




测试: 
Java代码  收藏代码
  1.     package com.gjy.DynamicProxy;  
  2. public class TestTank {  
  3.         public static void main(String[] args) throws Exception{  
  4.             Tank t = new Tank();  
  5. Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(t));  
  6.             moveable.move();  
  7.           
  8.         }  
  9. }  

创建文件夹工具类:MakFileUtil 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.util.StringTokenizer;  
  6.   
  7. public class MakFileUtil {  
  8.         public static void createFile(String pathstr) throws IOException{  
  9. //      File dirFile;  
  10. //      boolean bFile;  
  11. //      bFile = false;  
  12. //    
  13. //      dirFile = new File("E:\\test");  
  14. //      bFile = dirFile.exists();  
  15. //    
  16. //      if( bFile == true ){  
  17. //          System.out.println("The folder exists.");  
  18. //      }else{  
  19. //  System.out.println("The folder do not exist,now trying to create a one...");  
  20. //          bFile = dirFile.mkdir();  
  21. //          if( bFile == true ){  
  22. //              System.out.println("Create successfully!");  
  23. //          }else{  
  24. //  System.out.println("Disable to make the folder,please check the disk is full or not.");  
  25. //          System.exit(1);  
  26. //      }  
  27.             //创建多级目录  
  28.             String path = pathstr;    
  29. //为指定字符串构造一个 string tokenizer。 "/"字符是分隔标记的分隔符。分隔符字符本身不作为标记。  
  30.             StringTokenizer st = new StringTokenizer(path,"/");    
  31.             String path1 = st.nextToken()+"/";    
  32.             String path2 = path1;    
  33.                 while(st.hasMoreTokens())    
  34.             {    
  35.                 path1 = st.nextToken()+"/";    
  36.                 path2 += path1;  
  37.                 File inbox = new File(path2);    
  38.                 if(!inbox.exists())    
  39.                         inbox.mkdir();    
  40.             }   
  41.         }  
  42. }  

以上就是动态代理的一个模拟实现,测试时我们不管Proxy和InvocationHandler是怎么实现的,我们只要实现InvocationHandler接口完成相应的逻辑,然后调用Proxy 
的newProxyIntenct(Class infac, InvocationHandler h) 传入相应的接口,和InvocationHandler的实现类就可以实现对被代理对象的代理。也就是说Proxy和InvocationHandler写好之后永远不变。 

在运行过程中Proxy会动态生成代理主题角色,示例中生成的代理主题角色的代码如下: 
Java代码  收藏代码
  1. import java.lang.reflect.Method;  
  2. public class $Proxy implements com.gjy.DynamicProxy.Moveable{  
  3.         private com.gjy.DynamicProxy.InvocationHandler h;  
  4.         public $Proxy(MakFileUtil h) {  
  5.             super();  
  6.             this.h = h;  
  7.         }  
  8.         @Override  
  9.         public void move() {  
  10.             try {  
  11. Method md =com.gjy.DynamicProxy.Moveable.class.getMethod("move");  
  12.                 h.invoke(this,md);  
  13.             }catch (Exception e){   
  14.                 e.printStackTrace();  
  15.             }  
  16.         }  
  17. }  

如果我们想在Tank的move()方法被调用的前后加入其它的逻辑处理,我们只需实现InvocationHandler接口,下面是给move()加日志: 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. public class LogInvocationHandler implements InvocationHandler {  
  6.             private Object target;  
  7.         public LogInvocationHandler(Object target) {  
  8.             super();  
  9.             this.target = target;  
  10.         }  
  11.         @Override  
  12.         public void invoke(Object o, Method m) {  
  13.             System.out.println("Tank start...........");  
  14.                 try {  
  15.                 m.invoke(target);  
  16.             } catch (Exception e) {  
  17.                 e.printStackTrace();  
  18.             }  
  19.             System.out.println("Tank stop..............");  
  20.         }  
  21. }  


测试: 
Java代码  收藏代码
  1. package com.gjy.DynamicProxy;  
  2.   
  3. public class TestTank {  
  4.         public static void main(String[] args) throws Exception{  
  5.             Tank t = new Tank();  
  6. Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(t));  
  7. Moveable moveable2 = (Moveable) Proxy.newProxyIntenct(Moveable.classnew LogInvocationHandler(moveable));  
  8.             moveable2.move();  
  9.         }  
  10. }  






动态代理:

java 动态代理深度学习,

一.相关类及其方法:

java.lang.reflect.Proxy,
Proxy 提供用于创建动态代理类和实例的静态方法.
newProxyInstance()
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
(详见api文档)

java.lang.reflect.InvocationHandler,
InvocationHandler 是代理实例的调用处理程序 实现的接口。 
invoke()
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
(详见api文档)

二.源代码:

被代理对象的接口及实现类:
package com.ml.test;

public interface Manager {
public void modify();
}

package com.ml.test;

public class ManagerImpl implements Manager {

@Override
public void modify() {
   System.out.println("*******modify()方法被调用");
}
}

业务代理类:
package com.ml.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class BusinessHandler implements InvocationHandler {

private Object object = null;

public BusinessHandler(Object object) {
   this.object = object;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
   System.out.println("do something before method");
   Object ret = method.invoke(this.object, args);
   System.out.println("do something after method");
   return ret;

}
}



客户端类:
package com.ml.test;
import java.lang.reflect.Proxy;
public class Client {

public static void main(String[] args) {
   // 元对象(被代理对象)
   ManagerImpl managerImpl = new ManagerImpl();

   // 业务代理类
   BusinessHandler securityHandler = new BusinessHandler(managerImpl);

   // 获得代理类($Proxy0 extends Proxy implements Manager)的实例.
   Manager managerProxy = (Manager) Proxy.newProxyInstance(managerImpl
     .getClass().getClassLoader(), managerImpl.getClass()
     .getInterfaces(), securityHandler);

   managerProxy.modify();
}
}

三.执行结果:
do something before method
*******modify()方法被调用
do something after method

四.机制分析:

Proxy.(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事.
(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy.
$Proxy0类实现了interfaces的接口,并继承了Proxy类.
(2)实例化$Proxy0并在构造方法中把BusinessHandler传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,如下:
class Proxy{
   InvocationHandler h=null;
   protected Proxy(InvocationHandler h) {
    this.h = h;
   }
   ...
}



下面是本例的$Proxy0类的源码(好不容易才把它提出来):


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Manager {

private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;

static {
   try {
    m1 = Class.forName("java.lang.Object").getMethod("equals",
      new Class[] { Class.forName("java.lang.Object") });
    m0 = Class.forName("java.lang.Object").getMethod("hashCode",
      new Class[0]);
    m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
      new Class[0]);
    m2 = Class.forName("java.lang.Object").getMethod("toString",
      new Class[0]);
   } catch (NoSuchMethodException nosuchmethodexception) {
    throw new NoSuchMethodError(nosuchmethodexception.getMessage());
   } catch (ClassNotFoundException classnotfoundexception) {
    throw new NoClassDefFoundError(classnotfoundexception.getMessage());
   }
}

public $Proxy0(InvocationHandler invocationhandler) {
   super(invocationhandler);
}

@Override
public final boolean equals(Object obj) {
   try {
    return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
      .booleanValue();
   } catch (Throwable throwable) {
    throw new UndeclaredThrowableException(throwable);
   }
}

@Override
public final int hashCode() {
   try {
    return ((Integer) super.h.invoke(this, m0, null)).intValue();
   } catch (Throwable throwable) {
    throw new UndeclaredThrowableException(throwable);
   }
}

public final void modify() {
   try {
    super.h.invoke(this, m3, null);
    return;
   } catch (Error e) {
   } catch (Throwable throwable) {
    throw new UndeclaredThrowableException(throwable);
   }
}

@Override
public final String toString() {
   try {
    return (String) super.h.invoke(this, m2, null);
   } catch (Throwable throwable) {
    throw new UndeclaredThrowableException(throwable);
   }
}
}

接着把得到的$Proxy0实例强制转换成Manager.
当执行managerProxy.modify()方法时,就调用了$Proxy0类中的modify()方法.
在modify方法中,调用父类Proxy中的h的invoke()方法.
即InvocationHandler.invoke();



你可能感兴趣的:(JAVA代理学习)