动态代理的实现

一.我对动态代理的理解

1.动态生成代理类java源文件
2.将代理类java源文件编译为代理类class字节码文件
3.将代理类class字节码文件 自动加载到内存中
4.将自动加载到内存的代理类class字节码进行实例化为 代理对象
5.有了代理对象,就可以使用代理对象中的方法调用被代理对象的方法了;

二.动态代理的实现流程

点击查看代码演示

1.编写接口MoveAble 有move方法

package proxy.statics;
/**
 * 移动接口
 * @author lxf
 *
 */
public interface MoveAble {
    public  void move();
}

2.编写被代理类Car实现MoveAble接口,并实现move方法写业务罗辑;

package proxy.statics;
import java.util.Random;
/**
 * 被代理类,汽车
 * @author lxf
 * @2017-07-06
 */
public class Car implements MoveAble {

    @Override
    public void move() {
        //System.out.println("被代理对象---我是汽车对象本身:"+this.getClass().getName());
       //实现开车
       try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽车行驶中...");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

3.编写InvocationHandler接口(包含myinvoke方法)
注意:这里的InvocationHandler并不是java.lang.refect包下面的InvocationHandler

package proxy.dynamic.custom;
import java.lang.reflect.Method;
/**
 * 事务处理接口
 * @author lxf
 *
 */
public interface InvocationHandler {
    /**
     * 参数:Object obj 属于代理对象
     * 参数:Method method 属于代理对象的方法
     */
    public void myinvoke(Object obj, Method method);
}

4.编写TimerHandler类实现自己InvocationHandler接口中的myinvoke方法(用来调用被代理对象的方法,还有其他额外的业务逻辑)

package proxy.dynamic.custom;
import java.lang.reflect.Method;
/**
 * 实现自己定义的事务处理接口proxy.dynamic.custom.InvocationHandler
 * @author lxf
 *
 */
public class TimerHandler implements  InvocationHandler {
    //代理对象
    private Object target;
   
    public TimerHandler(Object target) {
        super();
        this.target = target;
    }

    /**
     * 参数:Object obj 属于代理对象
     * 参数:Method method 属于代理对象的方法
     */
    @Override
    public void myinvoke(Object obj, Method method) {
        // TODO Auto-generated method stub
        try {
            //开始时间 " + br + 
            Long start = System.currentTimeMillis(); 
            System.out.println("汽车开始行驶...");
            method.invoke(target);
            //结束时间 " + br + 
            Long end = System.currentTimeMillis(); 
            System.out.println("汽车结束行驶...行驶话费了:" + (end-start) + "ms"); 
            //视频听到3-3 3:42秒
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
}

3.编写生成代理类的类Proxy,它的主要功能是 一步骤 中的所有流程;

package proxy.dynamic.custom;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
import javax.tools.JavaCompiler.CompilationTask;
import proxy.statics.Car;
import proxy.statics.MoveAble;
/**
 * 动态代理类
 * @author lxf
 * 参数:
 * Class 代理类和被代理类实现的接口
 *  InvocationHandler h 自己实现的事务处理器proxy.dynamic.custom.TimerHandler
 *
 */
public class Proxy {
    
    /**
     * 自己实现JDK生成动态代理类及对象
     * @param infce 接口class,有了接口就可以通过接口获取接口中定义的方法,为生成代理类而用
     * @param h 自己创建的proxy.dynamic.custom.InvocationHandler 事务处理器(处理主要业务罗辑)
     *       事务处理器中包含被代理对象Car,具体处理业务罗辑的代码
     * @return
     * @throws IOException
     */
    public static Object newProxyInstance(Class infce, InvocationHandler h) throws IOException
    {
        String br = "\n"; //换行符
        String methodStr = "";
        //获取接口中所有的方法,遍历组合为代理类的方法
        for(Method m : infce.getMethods()){
            methodStr += "  @Override" + br +
            "   public void " + m.getName() + "() {" + br +
            "  try{" + br +
            "  Method md = " + infce.getName() + ".class.getMethod(\"" 
                                        + m.getName() + "\");" + br +
            "  h.myinvoke(this,md);" +br+ 
            "  }catch(Exception e){ e.printStackTrace();}" + br +
            "   }" ;
        }
        
        /**
         * 动态代理类字符串
         */
        String str = 
        " package proxy.dynamic.custom; " + br + 
        " import proxy.dynamic.custom.InvocationHandler; " + br +
        "  import java.lang.reflect.Method;" + br +
        " public class $Proxy0  implements "+infce.getName()+"{ " + br + 
         "  private InvocationHandler h; " + br + 
         "   public $Proxy0( InvocationHandler h ) " + br + 
         "  { " + br + 
         "       this.h = h; " + br + 
         "  } " + br +
         methodStr + br +
        "}";
        
        /*
         * 自行实现动态代理的流程
         * 1. 动态生成代理类.java源文件
         */
        //获取当前项目路径,/home/lxf/workspaceEE/proxy
        String filename = System.getProperty("user.dir") + "/bin/proxy/dynamic/custom/$Proxy0.java";
        System.out.println(filename);
        File file = new File(filename);
        FileUtils.writeStringToFile(file, str);
        
        /*
         * 2. 将动态生成的代理类.java源文件编译为class字节码文件
         */
        //编译
        //拿到编译器
        JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
        //文件管理者
        StandardJavaFileManager fileMgr = 
                complier.getStandardFileManager(null, null, null);
        //获取文件
        Iterable units = fileMgr.getJavaFileObjects(filename);
        //编译任务
        CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
        //进行编译
        t.call();
        fileMgr.close();
           
       /**
        * load到内存中
        */
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c;
        try {
            c = cl.loadClass("proxy.dynamic.custom.$Proxy0");
            //System.out.println(c.getName());
            //通过构造器返回代理对象
            Constructor ctr = c.getConstructor(InvocationHandler.class);
            return ctr.newInstance(h);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       return null;
    }
}

4.测试

package proxy.dynamic.custom;
import java.io.IOException;
import proxy.statics.Car;
import proxy.statics.MoveAble;
/**
 * 测试自己实现JDK动态代理实现思路
 * @author lxf
 * @date 2017-07-07
 */
public class testMain {
    public static void main(String[] args) throws IOException
    {
        //实例化被代理类
        Car car = new Car();
        //实例化事务处理器
        InvocationHandler h = new TimerHandler(car);
        //生成代理对象
        MoveAble m = (MoveAble)Proxy.newProxyInstance(MoveAble.class,h);
        //调用代理对象的方法
        m.move();
    }    
}

执行结果:

/home/lxf/workspaceEE/proxy/bin/proxy/dynamic/custom/$Proxy0.java
汽车开始行驶...
汽车行驶中...
汽车结束行驶...行驶话费了:975ms

动态生成代理类/home/lxf/workspaceEE/proxy/bin/proxy/dynamic/custom/$Proxy0.java的代码如下:

 package proxy.dynamic.custom; 
 import proxy.dynamic.custom.InvocationHandler; 
  import java.lang.reflect.Method;
 public class $Proxy0  implements proxy.statics.MoveAble{ 
  private InvocationHandler h; 
   public $Proxy0( InvocationHandler h ) 
  { 
       this.h = h; 
  } 
  @Override
   public void move() {
  try{
  Method md = proxy.statics.MoveAble.class.getMethod("move");
  h.myinvoke(this,md);
  }catch(Exception e){ e.printStackTrace();}
   }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容