java代理模式学习

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

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

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

Java代码  

  1. package com.gjy.proxy;
  2. blic interface Moveable {
  3. void move();

代理主题角色:TanktimeProxy

Java代码  

  1. package com.gjy.proxy;
  2. public class TanktimeProxy implements Moveable{
  3. private Moveable t;
  4. public TanktimeProxy(Moveable t) {
  5. super();
  6. this.t = t;
  7. }
  8. @Override
  9. public void move() {
  10. long time1 = System.currentTimeMillis();
  11. System.out.println("time1="+time1);
  12. t.move();
  13. long time2 = System.currentTimeMillis();
  14. System.out.println("time2="+time2);
  15. System.out.println("运行时间为:"+(time2-time1));
  16. }
  17. }

实际被代理对象:Tank

Java代码  

  1. package com.gjy.proxy;
  2. public class Tank implements Moveable{
  3. @Override
  4. public void move() {
  5. System.out.println("TanK moving........");
  6. }
  7. }

测试:

Java代码  

  1. package com.gjy.proxy;
  2. public class TestTank {
  3. public static void main(String[] args) {
  4. Tank t = new Tank();
  5. Moveable move = new TanktimeProxy(t);
  6. move.move();
  7. }
  8. }

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

下面我想在TanK的move()方法前后加上日志: 
我必需再写一个类来实现这一功能:

Java代码  

  1. package com.gjy.proxy;
  2. public class TanklogProxy implements Moveable{
  3. private Moveable t;
  4. public TanklogProxy(Moveable t) {
  5. super();
  6. this.t = t;
  7. }
  8. @Override
  9. public void move() {
  10. System.out.println("start move........");
  11. t.move();
  12. System.out.println("end move......");
  13. }
  14. }

测试:

Java代码  

  1. package com.gjy.proxy;
  2. public class TestTank {
  3. public static void main(String[] args) {
  4. Tank t = new Tank();
  5. Moveable move = new TanktimeProxy(t);
  6. Moveable movet = new TanklogProxy(move);
  7. movet.move();
  8. }
  9. }

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

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

下面是一个简单的动态代理的实现: 
类图如下: 

首先编写一个生成代理主题角色的类:Proxy

Java代码  

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

代理对象的操作接口:

Java代码  

  1. package com.gjy.DynamicProxy;
  2. import java.lang.reflect.Method;
  3. public interface InvocationHandler {
  4. void invoke(Object o,Method m);
  5. }

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

TimeInvocationHandler实现InvocationHandler接口:

Java代码  

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

实际被代理对象:Tank

Java代码  

  1. package com.gjy.DynamicProxy;
  2. ublic class Tank implements Moveable{
  3. @Override
  4. public void move() {
  5. int a = 5;
  6. int b = 6;
  7. int c = 0;
  8. int d = 0;
  9. for (int i = 0; i < 1000; i++) {
  10. d = i;
  11. }
  12. c = ((a+b)/2)*12;
  13. System.out.println("TanK moving..Tank 的速度是"+c);
  14. }

抽象代理主题: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. }

创建文件夹工具类:MakFileUtil

Java代码  

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

以上就是动态代理的一个模拟实现,测试时我们不管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. import java.lang.reflect.Method;
  3. public class LogInvocationHandler implements InvocationHandler {
  4. private Object target;
  5. public LogInvocationHandler(Object target) {
  6. super();
  7. this.target = target;
  8. }
  9. @Override
  10. public void invoke(Object o, Method m) {
  11. System.out.println("Tank start...........");
  12. try {
  13. m.invoke(target);
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. System.out.println("Tank stop..............");
  18. }
  19. }

测试:

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 moveable2 = (Moveable) Proxy.newProxyIntenct(Moveable.class, new LogInvocationHandler(moveable));
  7. moveable2.move();
  8. }
  9. }

同样代理顺序可以交换,这就是动态代理的实现过程。

java代理模式学习

时间: 2024-07-30 13:47:59

java代理模式学习的相关文章

设计模式学习--------12.代理模式学习

场景: 福尔摩斯一直想送礼物给花生,但是羞于直接赠送,于是想到让房东太太去帮忙送礼物.编程如何实现呢? 定义: 为其他对象提供一种代理以控制对这个对象的访问. 角色: Proxy:代理对象.有下列功能: 实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象. 持有一个具体目标对象的引用,可以在需要时调用具体的目标对象. 可以控制对目标对象的访问,并可以负责创建和删除它. package com.kris.study; public class Proxy implements

设计模式学习之代理模式学习(一)

关于设计模式想必学习过Java语言的人都知道吧,当时对其进行深入学习的的人应该不是很多.在我看来设计方面的知识相比于框架应用配置等知识要有意思的多,并且设计模式的对一个程序员的编程思想提升有着很大的帮助.但是设计模式有二十三种,想要全部掌握还是要花点时间的,但如果是只学习常用的几种设计模式还是相对容易的.下面是我学习代理模式的一些心得. 问题引出      什么是代理模式,为什么要用代理模式. 现在有一个场景模拟:有一个tank类,他实现了Moveable接口,Moveable接口中有一个mov

java 代理模式详解

java 动态代理(JDK和cglib) 设计模式这东东每次看到就明白可过段时间又不能很流利的说出来,今天就用详细的比喻和实例来加深自己的理解(小弟水平不高有不对的地方希望大家能指出来). (1)代理这个词生活中有很多比如在街边卖手机卡.充公交地铁卡的小商店他们都起了代理的作用,java中的代理跟这些小店商的作用是一样的.再比如我想在淘宝上开个服装店但又没有货源怎么办,这时候我就要跟淘宝上某一卖家联系做他的代理.我跟我的商家都要卖衣服(就好比我们都继承了卖衣服的接口sellClothesInte

Java代理模式

Java代理模式分为静态代理和动态代理模式 静态代理模式比较简单,直接上图和代码: 代理模式类图如下: 在代理模式中的角色: ● 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象. ● 目标对象角色:定义了代理对象所代表的目标对象. ● 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象:代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象.代理对象通常在客户端调用传递给目标对象之前或之后,执行某个

Java 代理机制学习总结

-------<a href="http://www.itheima.com/"">android培训</a>.<a href="http://www.itheima.com/" ">java培训</a>期待与您交流!---------- Java 代理机制学习总结 在编写程序时,除了要解决核心业务逻辑时还要编写一些与核心业务逻辑相关的系统服务代码.如日志,安全等代码.在没有使用java代理机制时,

Java代理模式——静态代理模式

一:代理模式 代理模式的作用是:为其他对象提供一种代理以控制这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 二:代理模式设计到的角色 抽象角色:声明真是对象和代理对象的共同接口(抽象类或接口). 代理角色:代理对象角色内部含有对真是对象的引用,从而可以操作真是对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真是对象.同时,代理对象可以在执行真实对象的操作时,附加其他操作,相当于对真是对象进行封装. 真实

Java 工厂模式学习

工厂模式分三种:简单工厂.工厂方法.抽象工厂.其中抽象工厂是用于多个产品族的情况.所谓产品族就是不同产品组成的有机整体,各不同产品之间相互依赖.打个比方,一台电脑有CPU.主板.内存和硬盘等,这些不同产品组成了一个产品族.就好比Dell和HP要把这些产品进行不同的组装,这时就需要用到抽象工厂.以下是代码演示: 简单工厂,可以用反射实现: 首先定义产品的抽象接口 package com.demo.SimpleFactory; public interface CPU { public void r

java 代理模式,观察者模式

代理模式1 [java] view plain copy import <a href="http://lib.csdn.net/base/17" class='replace_word' title="Java EE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.lang.reflect.InvocationHandler; import java

Java 代理模式

代理模式的概念:为其他对象提供一种代理一控制对这个对象的访问. 应用场景:在开发中一些业务类中方法,除了需求的操作,还需要进行其他的非业务操作.比如提供给app的接口.除了接口要实现的业务逻辑,还要对用户的信息,设备的信息进行验证,参数的加密解密.这种在每个接口方法前都要调用的,和业务代码参在一起就会重复,累赘.可以通过代理类将这些经常使用的方法抽取出来.业务类只用关心业务操作,降低耦合. 静态代理 代理和被代理对象在代理前是确定的.他们都实现了相同的接口或者继承了相同的抽象类. 动态代理 动态