手写JDK动态代理

付威     2019-07-23   6062   17min  

反射动态代理

为了能够更好实现AOP的思想,在Java中有了动态代理概念,与动态代理相对应的就是静态代理,首先看下面的代码。

public interface IWoker {
    String sayHello(String name,String code)  ;
}  

public class Worker  implements IWoker{
    @Override
    public String  sayHello(String name,String code) {
        System.out.println("hello");
    }
}

如果我们想在sayHello的方法前后分别都打印一条日志,实现AOP的思想,那使用静态代理的方法如下:

public class WorkerProxy {
    public void aopWorker(IWoker doWoker){
        System.out.println("before");
        doWoker.sayHello("Rz","Mz");
        System.out.println("end");
    }
}

定义一个WorkProxy的代理类,在执行方法的时候,使用代理类来执行:

Worker worker = new Worker();
new WorkerProxy().aopWorker(worker);

静态代理很好立即,即是使用组合类的方式来实现代理模式。这种形式的就是过于单一,代理的接口多的时候,就对应会产生很多代理类。

而java的动态代理就是为了解决这个问题,动态代理实现的代码如下:

//动态代理类
public class DynaminProxy implements InvocationHandler {
    private Object subject;
    public DynaminProxy(Object subject)
    {
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object obj = method.invoke(subject, args);
        System.out.println("end");
        return obj;
    }
}

代码调用:


 IWoker proxy = (IWoker) Proxy.newProxyInstance(
                IWoker.class.getClassLoader(),
                new Class[]{IWoker.class},
                new DynaminProxy(worker));
  proxy.sayHello();

从上面的代码可以看出,动态代理返回来的proxy对象很奇怪,通过调试可以看到对应的类型为:

Proxy对象

对于Proxy对象可以通过java语法分析如下:

  1. Proxy对象的类一定是实现了IWorker接口
  2. 执行方法的时候,是通过调用DynaminProxyinvoke方法来调用真正的方法

根据上面的推断,proxy的对象的代码应该是:

public class $Proxy implements IWoker {
    private DynaminProxy h;
    public $Proxy(DynaminProxy dynaminProxy) {
        this.h = dynaminProxy;
    }
    @Override
    public String  sayHello(String name,String code) {
        try {
            Method m = IWoker.class.getDeclaredMethod("sayHello", name.getClass(),code.getClass);
            Object invoke = this.h.invoke(null, m, new Object[]{name,code});
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
    }
}

使用代码进行的调用的时候,运行结果一致。在刚刚的代码中,如何实现的这个功能的呢?

Proxy.newProxyInstance(IWoker.class.getClassLoader(), new Class[]{IWoker.class}, new DynaminProxy(worker));

再观察动态代理的创建方式,有三个参数ClassLoader,Class的数组和最终的是执行的代码。

根据上面的代码,可以先确定代码实现的思路:

  1. 动态创建动态代理类$Proxy.java
  2. 编译成$Proxy.class
  3. 使用ClassLoader加载对应的类,创建对象返回。

根据上面的思路,可以编写代码如下:

创建$Proxy.java类,实现动态生成类

    StringBuilder classContent = new StringBuilder();
    classContent.append("package com.rz.frame.dynamicproxy;");
    Class targetInfo = clazz[0];
    String targetInfoName = targetInfo.getSimpleName();
    String dynamicName = obj.getClass().getSimpleName();
    classContent.append(" import ").append(targetInfo.getName()).append(";");
    classContent.append("import java.lang.reflect.Method;");
    classContent.append("public class $Proxy implements ").append(targetInfoName);
    classContent.append("{private ").append(dynamicName).append(" target;");
    classContent.append("public $Proxy(").append(dynamicName).append(" target){this.target=target;}");
    Method[] declaredMethods = targetInfo.getDeclaredMethods();
    for (Method m : declaredMethods) {
        String methodName = m.getName();
        Class returnTYpe = m.getReturnType();
        Class<?>[] parameterTypes = m.getParameterTypes();
        StringBuilder argContent = new StringBuilder();
        StringBuilder argsName = new StringBuilder();
        StringBuilder argsClass = new StringBuilder();
        int i = 0;
        for (Class param : parameterTypes) {
            String sName = param.getSimpleName();
            argContent.append(sName).append(" var").append(i).append(",");
            argsName.append(" var").append(i).append(",");
            argsClass.append(" var").append(i).append(".getClass(),");

            i++;
        }
        if (argContent.length() > 0) {
            argContent = new StringBuilder(argContent.substring(0, argContent.lastIndexOf(",")));
            argsName = new StringBuilder(argsName.substring(0, argsName.lastIndexOf(",")));
            argsClass = new StringBuilder(argsClass.substring(0, argsClass.lastIndexOf(",")));
        }
        classContent.append("public ").append(returnTYpe.getSimpleName()).append(" ").append(methodName).append("(").append(argContent).append("){");
        classContent.append(" try{Method m =").append(targetInfoName).append(".class.getDeclaredMethod(\"").append(methodName).append("\",").append(argsClass).append(");");

        classContent.append(" Object invoke = this.target.invoke(").append("this,m,new Object[]{ ").append(argsName).append("});");
        classContent.append("return (").append(returnTYpe.getSimpleName()).append(")invoke;} catch (Throwable ex) {return null;}}}");
    }

生成的类结果

package com.rz.frame.dynamicproxy;

import com.rz.frame.dynamicproxy.IWoker;

import java.lang.reflect.Method;

public class $Proxy implements IWoker {
    private DynaminProxy target;

    public $Proxy(DynaminProxy target) {
        this.target = target;
    }

    public String sayHello(String var0, String var1) {
        try {
            Method m = IWoker.class.getDeclaredMethod("sayHello", var0.getClass(), var1.getClass());
            Object invoke = this.target.invoke(this, m, new Object[]{var0, var1});
            return (String) invoke;
        } catch (Throwable ex) {
            return null;
        }
    }
}

把类写入文件,调用编译器编译成.class文件


    File file = new File(this.getClass().getResource("").getPath().concat("$Proxy.java"));
    FileWriter fw = new FileWriter(file);
    fw.write(classContent.toString());
    fw.flush();
    fw.close();

    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
    Iterable unit = fileManager.getJavaFileObjects(file);
    JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, null, null, unit);
    task.call();
    fileManager.close();

使用classloader加载class


    Class<?> aClass = classLoader.loadClass("com.rz.frame.dynamicproxy.$Proxy");
    Constructor<?> constructor = aClass.getConstructor(obj.getClass());
    Object o = constructor.newInstance(obj);
    return o;

(本文完)

作者:付威

博客地址:http://blog.laofu.online

如果觉得对您有帮助,可以下方的RSS订阅,谢谢合作

如有任何知识产权、版权问题或理论错误,还请指正。

本文是付威的网络博客原创,自由转载-非商用-非衍生-保持署名,请遵循:创意共享3.0许可证

交流请加群113249828: 点击加群   或发我邮件 laofu_online@163.com

付威

获得最新的博主文章,请关注上方公众号