设计模式之模拟实现动态代理

    代理顾名思义就是帮你去做某件事,你无需了解办事的过程和方法,动态代理就是可以帮适合任何人去做任何事,动态的去适应,就我们程序设计来说,就是可以代理任何类的任何方法,但不能去影响原来的类。spring的aop都用到了这样的思想。
    假设一个情景,你需要在不改变原类的前提下来给这个类的方法前和后加一段逻辑代码,该怎样实现?
    首先我们可以想到继承的方法,即继承原类,然后添加代码,但这样不太灵活,而且容易使类变得很多。所以我们采用另一种方法——聚合,即在目标类中new一个原类,再去添加代码。
    假设我们定义一个Moveable接口,如下定义:
package com.lxy.proxy;
public interface Moveable {
        public void move();
        public void stop();
}
    假设我们的原类为Car,实现了我们的Moveable接口,定义如下:
package com.lxy.proxy;
public class Car implements Moveable{
        @Override
        public void move() {
             System. out .println( "Car is Moving..." );
       }
        @Override
        public void stop() {
             System. out .println( "Car is stop..." );          
       }      
}
     下面就是我们定义的CarTimeProxy代理类,可以代理实现了Moveable接口的类,当然Car类也是可以代理的。
package com.lxy.proxy ;
public class CarTimeProxy implements Moveable {
       
        Moveable obj;
        public CarTimeProxy( Moveable obj) {
              super ();
              this . obj = obj;
       }
        @ Override
        public void move() {
             System. out.println("timeProxy start...");        //在方法前加的逻辑代码
              obj .move();
             System. out.println("timeProxy stop");            //在方法后加的逻辑代码
             
       }
 @Override
        public void stop() {
              System. out .println( "timeProxy start..." );          //在方法前加的逻辑代码
              obj .stop();
              System. out .println( "timeProxy stop" );            //在方法后加的逻辑代码
             
       }
}
    上面的代码虽然实现了要求但略显笨拙,我们并不需要知道这个代理类的存在,我们不需要关心他是如何实现的。再改改代码,既
然我们不需要关心代理类是如何让实现,那我们新建了一个Proxy类作为代理类,将上面的 CarTimeProxy拷贝为一个字符串,为简单
起见,我们只拷贝了move方法,然后再 将其编译,返回对象。
package com.lxy.proxy;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import  java.net.URL;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Proxy {
        public static Object newProxyInstance() throws Exception{
             String rt = "\r\n" ;
             String classStr =
                                "package com.lxy.proxy;" + rt +
                                "public class CarTimeProxy implements Moveable{" + rt +
                    
                                "      Moveable obj;" + rt +
                                "      public CarTimeProxy(Moveable obj) {" + rt +
                                "            super();" + rt +
                                "            this.obj = obj;" + rt +
                                "      }" + rt +
                                "      @Override" + rt +
                                "      public void move() {" + rt +
                                "             System.out.println(\"timeProxy start...\");" + rt +
                                "            obj.move();" + rt +
                                "             System.out.println(\"timeProxy stop\");" + rt +
                                "      }" + rt +
                                "}" ;
              //生成java文件
             String fileName = "G:/MyEclipse10workspace/proxy/CarTimeProxy.java" ;
             File f = new File(fileName);
             FileWriter fw;
              try {
                    fw = new FileWriter(f);
                    fw.write(classStr);
                    fw.flush();
                    fw.close();
             } catch (IOException e) {
                    e.printStackTrace();
             }
                    
              //compile编译
             JavaCompiler compiler = ToolProvider. getSystemJavaCompiler ();
             StandardJavaFileManager fileMgr = compiler.getStandardFileManager( null , null , null );
              Iterable units = fileMgr.getJavaFileObjects(fileName);
             CompilationTask t = compiler.getTask( null , fileMgr, null , null , null , units );
             t.call();
             fileMgr.close();
                    
              //load into memory and create an instance加载到内存创建对象
             URL[] urls = new URL[] { new URL( "file:/" + "G:/MyEclipse10workspace" )};
             URLClassLoader ul = new URLClassLoader(urls);
              Class c = ul.loadClass( "com.lxy.proxy.CarTimeProxy" );
             System. out .println(c);
              Constructor ctr = c.getConstructor(Moveable. class ) ;
             Moveable m = (Moveable)ctr.newInstance( new Car());
                         
              return m;
       }
}
    测试函数Main:
package com.lxy.proxy;

public class Main {

    public static void main(String[] args) throws Exception {
        
        Moveable Car = (Moveable)Proxy.newProxyInstance();
        Car.move();
    }

}
    如上我们算解决了一部分的问题,但还有关键性的问题摆在眼前,任何类和任何方法还有要加在原类方法前后的方法,该怎么实现呢?
针对以上的问题,我们可以将原类类型和前后的方法对象作为参数传给Proxy类,那么我们就需要定义一个方法接口InvocationHandler,代码如下:
package com.lxy.proxy;
import java.lang.reflect.Method;
public interface InvocationHandler {
        public void invoke(Object o, Method m);
}
    则Proxy类修改为:
package com.lxy.proxy;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import  java.net.URL;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Proxy {
        public static Object newProxyInstance( Class intFace, InvocationHandler handler) throws Exception{
             Method methods[] = intFace.getMethods();
              String rt = "\r\n" ;
              String mathedClassStr = "" ;
              for (Method me : methods){
                    mathedClassStr +=
                                     "      @Override" + rt +
                                     "      public void " + me.getName() + "() {" + rt +
                                     "      try {" + rt +
                                     "                   Method m = " + intFace.getName() + ".class.getMethod(\"" + me.getName() + "\");" + rt +
                                     "                   obj.invoke(this, m);" + rt +
                                     "      }catch(Exception e){ " + rt +
                                     "                   e.printStackTrace();" + rt +
                                     "            }" + rt +
                                     "      }" + rt ;
                    
             }
             
              String classStr =
                                "package com.lxy.proxy;" + rt +
                                "import java.lang.reflect.Method;" + rt +
                                "public class CarTimeProxy implements " + intFace.getName() + "{" + rt +
                    
                                "       com.lxy.proxy.InvocationHandler obj;" + rt +
                                "      public CarTimeProxy(InvocationHandler obj) {" + rt +
                                "            super();" + rt +
                                "            this.obj = obj;" + rt +
                                "      }" + rt +
                               mathedClassStr + rt +
                                "}" ;
                                 
              //生成java文件
              String fileName = "G:/MyEclipse10workspace/com/lxy/proxy/CarTimeProxy.java" ;
             File f = new File(fileName);
             FileWriter fw;
              try {
                    fw = new FileWriter(f);
                    fw.write(classStr);
                    fw.flush();
                    fw.close();
             } catch (IOException e) {
                    e.printStackTrace();
             }
                    
              //compile
             JavaCompiler compiler = ToolProvider. getSystemJavaCompiler ();
             StandardJavaFileManager fileMgr = compiler.getStandardFileManager( null , null , null );
              Iterable units = fileMgr.getJavaFileObjects(fileName);
             CompilationTask t = compiler.getTask( null , fileMgr, null , null , null , units );
             t.call();
             fileMgr.close();
                    
              //load into memory and create an instance
             URL[] urls = new URL[] { new URL( "file:/" + "G:/MyEclipse10workspace/" )};
             URLClassLoader ul = new URLClassLoader(urls);
              Class c = ul.loadClass( "com.lxy.proxy.CarTimeProxy" );
              Constructor ctr = c.getConstructor(InvocationHandler.class);
             Object m = ctr.newInstance(handler);
                          
              return m;
       }
}
    测试类Main
package com.lxy.proxy;
public class Main {
        /**
        * @param args
        * @throws Exception
        */
        public static void main(String[] args) throws Exception {
             Car c = new Car();
             InvocationHandler h =  new TimeHandler(c);
             Moveable Car = (Moveable)Proxy. newProxyInstance (Moveable. class , h);
             Car.move();
             Car.stop();
       }
}
    这样我们就模拟实现了动态代理,可以看出来我们模仿了jdk中动态代理的实现,只是简单的实现了下,还有些细节没有实现,比如方法中含有参数该怎么实现。
    本文参照了马士兵老师设计模式讲解中的代码和思想。


























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值