动态代理

案例

获取1个方法的运行时间

  • 使用继承实现(继承)

  • 使用实现接口实现(组合)

//继承
public class Tank {
    public void move() {
        System.out.println("Tank is moving ~~~");
    }
}
//继承基类重写里面的方法对其进行扩展(对Tank类的move()方法加上获取运行时间的代码)
public class TimeHandlerTank extends Tank {
    @Override
    public void move() {
        long start = System.currentTimeMillis();
        super.move();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("move时间: " + String.valueOf(end - start));
    }
}

public static void main(String[] args) {
    new TimeHandlerTank().move();
}
//结果
Tank is moveing~~~
move时间: 1003

//组合
public interface Moveable {
    void move();
}

public class Tank implements Moveable {

    public void move() {
        System.out.println("Tank is moveing~~~");
    }
}
//通过构造方法传入Tank
public class TimeHandler implements Moveable{
    private Moveable moveable ;

    public TimeHandler(Moveable moveable) {
        this.moveable = moveable;
    }

//实现move()方法的时候,调用Tank的move()方法,同时加上获取运行时间的代码
    public void move() {
        long start = System.currentTimeMillis();
        moveable.move();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("move时间: " + String.valueOf(end - start));
    }
}

public static void main(String[] args) {
    Moveable tank = new Tank();
    new TimeHandler(tank).move();
}

获取一个方法的执行时间同时记录日志

使用继承的方式就是继续继承重写方法,这样的话就会出现好多类(类爆炸),如果使用实现接口的方式(组合)将会避免这个问题。
//组合实现,对于上面组合的代码添加LogHandler类
public class LogHandler implements Moveable{
    private Moveable moveable;

    public LogHandler(Moveable moveable) {
        this.moveable = moveable;
    }

    public void move() {
        moveable.move();
        System.out.println("记录日志~~~~");
    }
}
//main方法修改如下:
public static void main(String[] args) {
    Moveable tank = new Tank();
    new LogHandler(new TimeHandler(tank)).move();
}
结果:
Tank is moveing~~~
move时间: 1005
记录日志~~~~

jdk动态代理

虽然可以通过编写hanler来扩展类,但是这样的话会产生的大量的类,如何能达到这样的效果又不产生大量的类呢 ,其实通过反射+动态编译便可以解决。其实jdk就是这样实现的,下面是jdk动态代理的例子:

//定义接口
public interface ForumService {
    void removeTopic(int topicId);
    void removeForum(int forumId);
}
//实现接口
public class ForumServiceImpl implements ForumService {
    public void removeTopic(int topicId) {
        System.out.println("模拟删除topic记录:" + topicId);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void removeForum(int forumId) {
        System.out.println("模拟删除formId:" + forumId);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//运行时间代码(横切代码)
public class PerformanceMonitor {

    public static void begin(String method){
        System.out.println("begin monitor...");
    }

    public static void end(){
        System.out.println("end monitor");
    }
}
//将目标业务类和横切代码编制在一起
public class PerformanceHandler implements InvocationHandler {
    private Object target;

    public PerformanceHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        PerformanceMonitor.begin(target.getClass().getName() + "." + method.getName());
        Object obj = method.invoke(target, args);
        PerformanceMonitor.end();
        return obj;
    }
}
//
public class TestForumService {
    public static void main(String[] args) {
        //希望被代理的目标类
        ForumService target = new ForumServiceImpl();
        //将目标业务类和横切代码编制在一起
        PerformanceHandler handler = new PerformanceHandler(target);
        //返回代理对象
        ForumService proxy = (ForumService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);

        proxy.removeForum(10);
        System.out.println("*****************");
        proxy.removeTopic(120);
    }
}

//结果:
begin monitor...
模拟删除formId:10
end monitor
*****************
begin monitor...
模拟删除topic记录:120
end monitor

模拟实现jdk动态代理

//定义被代理对象的类必须实现的接口
public interface Moveable {
   void move();
}
//被代理对象实现接口
public class Tank implements Moveable {

   public void move() {
      
      System.out.println("Tank Moving...");
      try {
         Thread.sleep(new Random().nextInt(10000));
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }
}
//反射调用被代理对象接口
public interface InvocationHandler {
   public void invoke(Object o, Method m);
}
//实现反射调用被代理对象接口
public class TimeHandler implements InvocationHandler {

    private Object target;

    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    public void invoke(Object o, Method m) {
        long start = System.currentTimeMillis();
        System.out.println("starttime:" + start);
        System.out.println(o.getClass().getName());
        try {
            m.invoke(target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("time:" + (end - start));
    }

}
//产生代理对象
public class Proxy {
   public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM
      String methodStr = "";
      String rt = "\r\n";
      
      Method[] methods = infce.getMethods();
      /*
      for(Method m : methods) {
         methodStr += "@Override" + rt + 
                   "public void " + m.getName() + "() {" + rt +
                     "   long start = System.currentTimeMillis();" + rt +
                     "   System.out.println(\"starttime:\" + start);" + rt +
                     "   t." + m.getName() + "();" + rt +
                     "   long end = System.currentTimeMillis();" + rt +
                     "   System.out.println(\"time:\" + (end-start));" + rt +
                   "}";
      }
      */
      for(Method m : methods) {
         methodStr += rt +
                   "public void " + m.getName() + "() {" + rt +
                   "    try {" + rt +
                   "    Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
                   "    h.invoke(this, md);" + rt +
                   "    }catch(Exception e) {e.printStackTrace();}" + rt +
                  
                   "}";
      }
      
      String src = 
         "package com.bjsxt.proxy;" +  rt +
         "import java.lang.reflect.Method;" + rt +
         "public class $Proxy1 implements " + infce.getName() + "{" + rt +
         "    public $Proxy1(InvocationHandler h) {" + rt +
         "        this.h = h;" + rt +
         "    }" + rt +
         
         
         "    com.bjsxt.proxy.InvocationHandler h;" + rt +
                     
         methodStr +
         "}";
      String fileName = 
         "/Users/wjk/myproject/test/design_pattern/src/main/java/com/bjsxt/proxy/$Proxy1.java";
      File f = new File(fileName);
      FileWriter fw = new FileWriter(f);
      fw.write(src);
      fw.flush();
      fw.close();
      
      //compile(Java动态编译)
      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:/" + "/Users/wjk/myproject/test/design_pattern/src/main/java")};
      URLClassLoader ul = new URLClassLoader(urls);
      Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");
      System.out.println(c);
      
      Constructor ctr = c.getConstructor(InvocationHandler.class);
      Object m = ctr.newInstance(h);
      //m.move();

      return m;
   }
}

public class Client {
   public static void main(String[] args) throws Exception {
      Tank t = new Tank();
     
      InvocationHandler h = new TimeHandler(t);
      
      Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);
      
      m.move();
   }
}
//结果
class com.bjsxt.proxy.$Proxy1
starttime:1452505387375
com.bjsxt.proxy.$Proxy1
Tank Moving...
time:9798

参考资料:

《Spring3.x企业应用开发实践》

《马士兵——设计模式》

转载于:https://my.oschina.net/u/2361475/blog/600829

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值