zoukankan      html  css  js  c++  java
  • 模拟实现jdk动态代理

    实现步骤

    1、生成代理类的源代码

    2、将源代码保存到磁盘

    3、使用JavaCompiler编译源代码生成.class字节码文件

    4、使用JavaCompiler编译源代码生成.class字节码文件

    5、返回代理类的实例

    实现代码

     
    package com.lnjecit.proxy.custom;
    
    import java.lang.reflect.Method;
    
    /**
     * 自定义InvocationHandler
     */
    public interface MyInvocationHandler {
    
        /**
         * 执行代理实例中目标方法,并返回结果
         * @param proxy 代理实例
         * @param method 目标方法
         * @param args 目标方法中的参数
         * @return
         */
        Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    package com.lnjecit.proxy.custom;
    
    import java.io.File;
    import java.lang.reflect.Constructor;
    
    /**
     * 自定义代理类
     *
     * @author
     * @create 2018-04-08 21:55
     **/
    public class MyProxy {
    
        /**
         * 生成代理类实例
         *
         * @param classLoader 类加载器
         * @param interfaces  被代理类实现的接口数组
         * @param h
         * @return
         */
        public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h) throws ClassNotFoundException {
            // 1、生成代理类的源代码
            String sourceFileStr = MyProxyGenerator.generateSourceFile("$Proxy0", interfaces);
            String filePath = MyProxy.class.getResource("/").getPath();
            try {
                // 2、将源代码保存到磁盘
                File sourceFile = MyProxyGenerator.saveGeneratedSourceFile(filePath, sourceFileStr);
                // 3、使用JavaCompiler编译源代码生成.class字节码文件
                MyProxyGenerator.generateProxyClass(sourceFile);
                // 4、使用ClassLoader将.class文件中的内容加载到JVM
                Class proxyClass = classLoader.findClass("$Proxy0");
                // 5、返回代理类的实例
                Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
                // 删除生成的源文件
                // sourceFile.delete();
                return c.newInstance(h);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }
    package com.lnjecit.proxy.custom;
    
    import javax.tools.*;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.reflect.Method;
    
    /**
     * 生成代理类
     *
     * @author
     * @create 2018-04-08 22:01
     **/
    public class MyProxyGenerator {
    
        private static final String PROXY_PACKAGE = "com.lnjecit.proxy.custom";
    
        private static final String LINE_FEED = "
    ";
    
        /**
         * 生成代理类的源代码
         * @param proxyName
         * @param interfaces
         * @return
         */
        public static String generateSourceFile(String proxyName, Class<?>[] interfaces) {
            StringBuffer buffer = new StringBuffer();
            buffer.append("package " + PROXY_PACKAGE + ";" + LINE_FEED);
            for (Class<?> intf : interfaces) {
                buffer.append("import " + intf.getName() + ";" + LINE_FEED);
            }
    
            buffer.append("import java.lang.reflect.Method;" + LINE_FEED);
            buffer.append("import com.lnjecit.proxy.custom.MyProxy;" + LINE_FEED);
            buffer.append("import com.lnjecit.proxy.custom.MyInvocationHandler;" + LINE_FEED);
            buffer.append("public final class " + proxyName + " extends MyProxy implements ");
            for (Class<?> intf : interfaces) {
                buffer.append(intf.getSimpleName());
            }
            buffer.append("{" + LINE_FEED);
    
            buffer.append("private MyInvocationHandler h;" + LINE_FEED);
            // 构造函数
            buffer.append("public " + proxyName + "(MyInvocationHandler h" + ") {" + LINE_FEED);
            buffer.append("this.h = h;" + LINE_FEED);
            buffer.append("}" + LINE_FEED);
    
            for (Class<?> intf : interfaces) {
                Method[] methods = intf.getMethods();
                for (int i = 0; i < methods.length; i++) {
                    Method method = methods[i];
                    buffer.append("public " + method.getReturnType() + " " + method.getName() + "()" + "{" + LINE_FEED);
                    buffer.append("try {" + LINE_FEED);
                    buffer.append("Method m = " + intf.getName() + ".class.getMethod("" + method.getName() + "",new Class[]{});" + LINE_FEED);
                    buffer.append("h.invoke(this, m, null);" + LINE_FEED);
                    buffer.append("}  catch (Throwable e) {" + LINE_FEED);
                    buffer.append("e.printStackTrace();" + LINE_FEED);
                    buffer.append("}" + LINE_FEED);
                    buffer.append("}" + LINE_FEED);
                }
    
            }
            buffer.append("}" + LINE_FEED);
            return buffer.toString();
        }
    
        /**
         * 将代理类源文件便以为.class文件
         * @param sourceFile 源文件
         * @throws IOException
         */
        public static void generateProxyClass(File sourceFile) throws IOException {
            // 获取JavaCompiler
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            // DiagnosticListener用于获取Diagnostic信息,Diagnostic信息包括:错误,警告和说明性信息
            DiagnosticListener<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
            // StandardJavaFileManager:用于管理与工具有关的所有文件
            StandardJavaFileManager manager = compiler.getStandardFileManager(diagnostics, null, null);
            // avaFileObjects: 是java源码文件(.java)和class文件(.class)的抽象
            Iterable iterable = manager.getJavaFileObjects(sourceFile);
            // 编译任务
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, iterable);
            task.call();
            manager.close();
        }
    
        /**
         * 将代理类的源代码保存到本地磁盘
         * @param filePath   文件保存路径
         * @param sourceFileStr 源代码
         * @throws IOException
         */
        public static File saveGeneratedSourceFile(String filePath, String sourceFileStr) throws IOException {
            File sourceFile = new File(filePath + PROXY_PACKAGE.replaceAll("\.", "/") + "/" + "$Proxy0.java");
            FileWriter fw = new FileWriter(sourceFile);
            fw.write(sourceFileStr);
            fw.flush();
            fw.close();
            return sourceFile;
        }
    }
    package com.lnjecit.proxy.custom;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /**
     * 自定义ClassLoader
     * @author
     * @create 2018-04-08 21:57
     **/
    public class MyClassLoader extends ClassLoader {
        
        private File baseDir;
    
        public MyClassLoader(){
            String basePath = MyClassLoader.class.getResource("").getPath();
            this.baseDir = new java.io.File(basePath);
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            String className = MyClassLoader.class.getPackage().getName() + "." + name;
            if(baseDir != null){
                File classFile = new File(baseDir,name.replaceAll("\.", "/") + ".class");
                if(classFile.exists()){
                    FileInputStream in = null;
                    ByteArrayOutputStream out = null;
                    try{
                        in = new FileInputStream(classFile);
                        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(null != out){
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        classFile.delete();
                    }
    
                }
            }
    
            return null;
        }
    }
    package com.lnjecit.proxy.custom;
    
    import java.lang.reflect.Method;
    
    /**
     * @author
     * @create 2018-04-08 21:59
     **/
    public class JDKDynamicProxy implements MyInvocationHandler {
    
        Object target;
    
        public <T> T getInstance(Object target) throws Exception {
            this.target = target;
            return (T) MyProxy.newProxyInstance(new MyClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Before invoke");
            Object result = method.invoke(target, args);
            System.out.println("After invoke");
            return result;
        }
    }

    测试代码

    package com.lnjecit.proxy;
    
    /**
     * Subject
     * 抽象主题接口
     * @author
     * @create 2018-03-29 14:16
     **/
    public interface Subject {
    
        void doSomething();
    }
    package com.lnjecit.proxy;
    
    /**
     * RealSubject
     * 真实主题类
     * @author
     * @create 2018-03-29 14:21
     **/
    public class RealSubject implements Subject {
        @Override
        public void doSomething() {
            System.out.println("RealSubject do something");
        }
    }
    import com.lnjecit.proxy.RealSubject;
    import com.lnjecit.proxy.Subject;
    
    /**
     * 测试类  
     * @author
     * @create 2018-04-08 23:07
     **/
    public class Client {
        public static void main(String[] args) {
            try {
                Subject subject = new JDKDynamicProxy().getInstance(new RealSubject());
                subject.doSomething();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    测试结果:

    Before invoke
    RealSubject do something
    After invoke

    在调试过程中可看到:在classpath路径下生成了$Proxy0.java和$Proxy0.class两个文件

     以上仅仅实现了代理一个接口并且方法无参数的简单代理,只是为了更好理解jdk动态代理。

  • 相关阅读:
    数据库设计
    Android入门
    Java
    深入理解计算机
    Python
    JS
    powerdesigner
    计算机程序员+研一生活总结
    影视剧里程序员使用的双显示屏,在生活中真的需要么?
    性质太恶劣,紧张时期竟有人开发假冒健康码软件,幸已下架!
  • 原文地址:https://www.cnblogs.com/zuidongfeng/p/8735250.html
Copyright © 2011-2022 走看看