手敲JDK动态代理实现

作者: 先生zeng | 来源:发表于2019-06-20 15:35 被阅读0次

    上一篇文章其实已经把动态代理底层实现讲的很清楚的,这篇想要直接上代码的,毕竟实现的步骤其实是差不多的。
    https://www.jianshu.com/p/72d1448a29f0
    步骤如下:
    1.新建一个XXXProxy类,然后获取一个代理类实例。
    2.新建一个XXXInvocationHandle抽象接口,还有invoke方法。
    3.新建一个类加载器,这样根据双亲委派机制,可以加载我们的代理类,每个类在JVM中都有各自的类加载器的,JVM本身有提供,我们也可以自己定义。
    4.重新newInstance方法,里面的生成步骤如下:
    // 1.动态生成源代码.java文件
    // 2.把java文件输出到磁盘
    // 3.把生成的.java文件编译成
    //获取系统编译器
    //4.编译生成的.class文件加载到jvm中来
    /编译完成后删除
    // 5.返回字节码重组以后新的代理对象。
    最后测试。

    直接撸代码了哈。

    ZXYProxy类如下:

    public class ZXYProxy{
    
        public static final String ln = "\r\n";
    
        public static Object newProxyInstance(ZXYClassLoader classLoader,Class<?> [] interfaces,ZXYInvocationHandle h){
    
                try {
    //         1.动态生成源代码.java文件
                    String src = generateSrc(interfaces);
    //         2.把java文件输出到磁盘
                    String path = ZXYProxy.class.getResource("").getPath();
                    System.out.println(path);
                    File f = new File(path + "$Proxy0.java");
                    FileWriter fw = new FileWriter(f);
                    fw.write(src);
                    fw.flush();
                    fw.close();
    //          3.把生成的.java文件编译成
                    //获取系统编译器
                    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                    StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
                    Iterable javaFileObjects = standardFileManager.getJavaFileObjects(f);
    
                    JavaCompiler.CompilationTask task = compiler.getTask(null,standardFileManager,null,null,null,javaFileObjects);
                    task.call();
                    standardFileManager.close();
    
                    //4.编译生成的.class文件加载到jvm中来
                    Class proxyClass = classLoader.findClass("$Proxy0");
                    Constructor constructor = proxyClass.getConstructor(ZXYInvocationHandle.class);
                    //编译完成后删除
                    f.delete();
    
                    //  5.返回字节码重组以后新的代理对象。
                    return constructor.newInstance(h);
    
                }catch (Exception e){
                    e.printStackTrace();
                }
            return null;
        }
    
        private static  String generateSrc(Class<?>[] interfaces){
            StringBuffer sb=new StringBuffer();
            sb.append("package com.zxy.test.gupao.tom.proxy.custom;" + ln);
            sb.append("import com.zxy.test.gupao.tom.proxy.staticed.Person;" + ln);
            sb.append("import java.lang.reflect.Method;" + ln);
            sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
    
            sb.append("ZXYInvocationHandle h;" + ln);
            sb.append("public $Proxy0(ZXYInvocationHandle h) {" + ln);
    
               sb.append("this.h = h;" + ln);
            sb.append("}" + ln);
    
            for(Method m : interfaces[0].getMethods()){
                sb.append("public "+ m.getReturnType()+" "+ m.getName() +"() {"+ ln);
                    sb.append("try {"+ln);
                        sb.append("Method m = "+interfaces[0].getName() +".class.getMethod(\""+m.getName()+"\",new Class[]{});"+ ln);
                        sb.append("this.h.invoke(this,m,null);"+ln);
                    sb.append("}catch(Throwable e){"+ln);
                    sb.append("e.printStackTrace();"+ln);
                    sb.append("}" + ln);
                sb.append("}");
            }
            sb.append("}"+ln);
    
            return sb.toString();
        }
    }
    

    ZXYInvocationHandle:
    ``java
    public interface ZXYInvocationHandle {

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    

    }

    接下来是类加载器
    ZXYClassLoader
    ```java
    public class ZXYClassLoader extends ClassLoader{
    
        private File classPathFile;
    
        public ZXYClassLoader(){
    
            String classPath = ZXYClassLoader.class.getResource("").getPath();
            this.classPathFile=new File(classPath);
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
    
            String className = ZXYClassLoader.class.getPackage().getName() + "." + name;
    
            if(classPathFile != null){
                File file = new File(classPathFile, name.replaceAll("\\.", "/")+".class");
                //字节读取
                if(file.exists()){
                    FileInputStream in=null;
                    ByteArrayOutputStream out=null;
    
                    try{
                        in=new FileInputStream(file);
                        out=new ByteArrayOutputStream();
                        byte[] buff = new byte[1024];
                        int len;
                        while((len = in.read(buff))!=-1){
                            out.write(buff,0,len);
                        }
                        return defineClass(className,out.toByteArray(),0,out.size());
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        if(null != in){
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
    
                        if(out!=null){
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            return null;
        }
    }
    

    然后是媒婆代理类:

    public class CustomerMeiPo implements ZXYInvocationHandle{
    
        private Person target;
    
        public Object getInstance(Person target)throws Exception{
            this.target=target;
    
            Class<? extends Person> aClass = target.getClass();
    
            return ZXYProxy.newProxyInstance(new ZXYClassLoader(),aClass.getInterfaces(),this);
    
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
            System.out.println("开始物色");
    
            method.invoke(this.target,args);
    
            System.out.println("如果合适的话,就准备办事");
            return null;
        }
    }
    

    还有一个代理类的接口,没什么哈。

    public interface Person {
    
        public void findLove();
    
        public void zufangzi();
    
        public void buy();
    
        public void findJob();
    
        //......
    }
    

    这是被代理类。

    public class XieMu implements Person {
    
        @Override
        public void findLove(){
            System.out.println("高富帅");
            System.out.println("身高180cm");
            System.out.println("胸大,6块腹肌");
    
        }
    
        @Override
        public void zufangzi() {
            System.out.println("租房子");
        }
    
        @Override
        public void buy() {
            System.out.println("买东西");
        }
    
        @Override
        public void findJob() {
            System.out.println("月薪20K-50k");
            System.out.println("找工作");
        }
    }
    

    最后,终于结束了。测试类:

    public class ZXYProxyTest {
    
        public static void main(String[] args) {
    
            try {
                Person obj = (Person)new CustomerMeiPo().getInstance(new XieMu());
                System.out.println(obj.getClass());
                obj.findLove();
                //打印出来
                byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
                FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
                os.write(bytes);
                os.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    结果如下:

    image.png

    还差一点,去我们的E盘看看,已经编译好一个代理类了。跟JDK实现的是一样的。


    ok,撸完收工!

    然后如果没感觉我这篇文章都在贴代码,可以看我的上一篇文章。详细讲解了JDK是怎么实现了。步骤是一样一样的。

    可能有的看到了,我是看视频学习的,嗯,不过每行代码还有源码分析都是自己去分析的。每行都是自己敲的,整理分享不易,希望大家多多支持。

    感谢您阅读我的文章,如果满意可以帮我点赞,谢谢哈。
    如果对文章部分还有什么见解或者疑惑,可以私信评论我,欢迎技术讨论。如果需要获取完整的文件资源,可以加我微信z985085305,获取我整理的全套笔记。
    思想的碰撞最能促进技术的进步哦。

    相关文章

      网友评论

        本文标题:手敲JDK动态代理实现

        本文链接:https://www.haomeiwen.com/subject/yoykqctx.html