zoukankan      html  css  js  c++  java
  • Java-马士兵设计模式学习笔记-代理模式-动态代理 修改成可以任意修改代理逻辑

    一、概述

    1.目标:动态代理的代理逻辑可以任意修改

    2.思路:

    (1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler) 

    (2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑

    3.知识点:

    (1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");

    (2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\.");

    二、代码

    1.InvocationHandler.java

    2.TimeHandler.java

    3.Movable.java

    4.Tank.java

    5.Proxy.java

    6.Client.java

    1.InvocationHandler.java

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

    2.TimeHandler.java

     1 package proxy;
     2 
     3 import java.lang.reflect.InvocationTargetException;
     4 import java.lang.reflect.Method;
     5 
     6 public class TimeHandler implements InvocationHandler {
     7 
     8     //保留被代理的对象
     9     private Object target;
    10     
    11     public TimeHandler(Object target) {
    12         this.target = target;
    13     }
    14 
    15     @Override
    16     public void invoke(Object o, Method m) {
    17         System.out.println("Time Proxy start...........");
    18         long start = System.currentTimeMillis();
    19         try {
    20             //除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去
    21             m.invoke(target);    
    22         } catch (Exception e) {
    23             e.printStackTrace();
    24         } 
    25         long end = System.currentTimeMillis();
    26         System.out.println("花费时间:"+(end - start));
    27         System.out.println("Time Proxy end...........");
    28 
    29     }
    30 
    31 }

    3.Movable.java

    1 package proxy;
    2 
    3 public interface Movable {
    4     public void move();
    5     public void stop();
    6 }

    4.Tank.java

     1 package proxy;
     2 
     3 import java.util.Random;
     4 
     5 public class Tank implements Movable {
     6 
     7     @Override
     8     public void move() {
     9         System.out.println("Tank moving.......");
    10         try {
    11             Thread.sleep(new Random().nextInt(2000));
    12         } catch (InterruptedException e) {
    13             e.printStackTrace();
    14         }
    15     }
    16 
    17     @Override
    18     public void stop() {
    19         System.out.println("Tank stopping.......");
    20         
    21     }
    22 
    23 }

    5.Proxy.java

     1 package proxy;
     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.JavaCompiler.CompilationTask;
    12 import javax.tools.StandardJavaFileManager;
    13 import javax.tools.ToolProvider;
    14 
    15 public class Proxy {
    16 
    17     public static Object newProxyInstance(Class interfze,InvocationHandler handler) throws Exception {
    18         
    19         String rt = "
    
    ";
    20         
    21         //拼接"实现接口方法"的字符串
    22         String methodStr = "";
    23         for(Method m: interfze.getMethods() ){
    24             
    25             //取出方法的修饰符和返回值类型
    26             String [] parts = m.toString().replace("abstract ", "").split("\.");
    27             String [] parts2 = parts[0].split(" ");
    28             
    29             methodStr +=
    30             "@Override" + rt +
    31             parts2[0]+" "+parts2[1]+" "+m.getName()+"() {" + rt +
    32             "try{"+ rt +
    33                 "java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(""+m.getName()+"");" + rt +
    34                 //传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target)
    35                 "handler.invoke(this, md);" + rt +
    36             "}catch(Exception e){"+ rt +
    37             "    e.printStackTrace();" + rt +
    38             "}" + rt +
    39             
    40                 
    41             "}"+ rt ;
    42         }
    43         
    44         
    45         //动态代理文件的源码
    46         String str = 
    47         "package proxy;" + rt +
    48 
    49         "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+
    50 
    51             
    52             //聚合Handler
    53             "private InvocationHandler handler;" + rt +
    54             
    55             "public TankTimeProxy(InvocationHandler handler) {" + rt +
    56                 "this.handler = handler;" + rt +
    57             "}" + rt +
    58 
    59             methodStr + rt +
    60 
    61         "}" ;
    62         
    63         //把源码写到java文件里
    64         File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java");
    65         FileWriter fw = new FileWriter(file);
    66         fw.write(str);
    67         fw.flush();
    68         fw.close();
    69         
    70         //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
    71         JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
    72         
    73         //文件管事器
    74         StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
    75         
    76         //编译单元
    77         Iterable units = fileMgr.getJavaFileObjects(file);
    78         
    79         //编译任务
    80         CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);
    81         
    82         //编译
    83         t.call();    
    84         fileMgr.close();
    85         
    86         //把类load到内存里
    87         URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")};
    88         URLClassLoader uc = new URLClassLoader(urls);
    89         Class c = uc.loadClass("proxy.TankTimeProxy");
    90         
    91         //生成实例
    92         //return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
    93         //Constructor ctr = c.getConstructor(interfze);
    94         Constructor ctr = c.getConstructor(InvocationHandler.class);
    95         return ctr.newInstance(handler);
    96     }
    97 }

    6.Client.java

     1 package proxy;
     2 
     3 import java.io.IOException;
     4 
     5 import org.junit.Test;
     6 
     7 public class Client {
     8 
     9     @Test
    10     public void testProxy() throws Exception{
    11         
    12         Movable m = (Movable)Proxy.newProxyInstance(Movable.class, new TimeHandler(new Tank()));
    13         m.move();
    14         m.stop();
    15         
    16     }
    17 }

    三、运行结果

  • 相关阅读:
    帧同步优化难点及解决方案
    四元数
    臭鼬管理法
    十分钟理解Gradle
    深入理解Android之Gradle
    走出体制的臭鼬工厂,臭鼬著名的“14条”管理原则
    Unity5-ABSystem(五):AssetBundle内存
    Unity5-ABSystem(四):AssetBundle依赖
    Unity5-ABSystem(三):AssetBundle加载
    ASP.NET Core搭建多层网站架构【2-公共基础库】
  • 原文地址:https://www.cnblogs.com/shamgod/p/4593287.html
Copyright © 2011-2022 走看看