模拟实现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动态代理。

原文地址:https://www.cnblogs.com/zuidongfeng/p/8735250.html