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动态代理。

  • 相关阅读:
    古谚、评论与论断、名篇与名言
    重读《西游记》
    重读《西游记》
    命名之法 —— 时间、季节、地点
    命名之法 —— 时间、季节、地点
    文言的理解 —— 古时的称谓、别称、别名
    文言的理解 —— 古时的称谓、别称、别名
    Oracle GoldenGate for Oracle 11g to PostgreSQL 9.2.4 Configuration
    瀑布 敏捷 文档
    POJ 1325 ZOJ 1364 最小覆盖点集
  • 原文地址:https://www.cnblogs.com/zuidongfeng/p/8735250.html
Copyright © 2011-2022 走看看