简单实现动态代理(Proxy)

Posted michaelpl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单实现动态代理(Proxy)相关的知识,希望对你有一定的参考价值。

  最近学习了Jdk的动态代理,然后自己也简单的手写了一个。
  
  思路:
      1.根据代理的接口,生成对应的Java代码文件
      2.将生成的Java文件编译成class文件
      3.利用URLClassLoader加载class到Jvm中,利用反射在new出这个对象。


代理业务接口
package com.michael.pl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public interface InvocationHandler {

    Object invock(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;

}

 

需要代理的接口


package com.michael.pl.service;

public interface LogService {

    void sayHi() throws Exception;

    Object out(String text) throws Exception;

}

package com.michael.pl.service.impl;

import com.michael.pl.service.LogService;

public class LogServiceImpl implements LogService {

    @Override
    public void sayHi() {

        System.out.println("hello");

    }

    @Override
    public Object out(String text) {
        return text;
    }
}

 

实现动态代理的核心类
技术图片
package com.michael.pl;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class MyProxy {

    public static final String TABLE = "    ";
    public static final String ENTER = "
";

    public static Object newProxyInstance(ClassLoader classLoader, Class<?> interfaceClass,
        InvocationHandler invocationHandler) throws Exception {

        String javaCode = buiderJavaFile(interfaceClass);
//        System.out.println(javaCode);

        String className = interfaceClass.getName().substring(interfaceClass.getName().lastIndexOf(".") + 1);
        File file = new File("\\com\\sun\\proxy\\$" + className + ".java");

        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }

        if (!file.exists()) {
            file.createNewFile();
        }

        // 把拼好的Java文件写到硬盘当中
        FileWriter fw = new FileWriter(file);
        fw.write(javaCode);
        fw.close();

        // 把写到硬盘的Java文件编译成class
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMgr.getJavaFileObjects(file);
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
        t.call();
        fileMgr.close();


        // 吧编译上的class文件加载到JVM中
        URL[] urls = new URL[]{new URL("file:G:\\\\")};


        URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class clazz = urlClassLoader.loadClass("com.sun.proxy.$" + className);

        Constructor constructor = clazz.getConstructor(InvocationHandler.class);
        return constructor.newInstance(invocationHandler);
    }

    /**
     * 生成对应的Java代码
     */
    public static String buiderJavaFile(Class<?> interfaceClass) throws Exception {

        String className = interfaceClass.getName().substring(interfaceClass.getName().lastIndexOf(".") + 1);

        StringBuilder content = new StringBuilder();
        content.append("package com.sun.proxy;" + ENTER );
        content.append("import java.lang.reflect.Method;" + ENTER);
        content.append("import java.lang.Exception;" + ENTER);
        content.append("import com.michael.pl.InvocationHandler;" + ENTER);
        content.append("public class $" + className + " implements " + interfaceClass.getName() + "{" + ENTER);

        content.append(TABLE + "private InvocationHandler i;" + ENTER);

        // 添加构造方法
        content.append(forTable(1) + " public $" + className + "(InvocationHandler i){"+ENTER);
        content.append(forTable(1) + "this.i = i;" + ENTER);
        content.append(forTable(1) + "}" + ENTER);


        Method[] methods = interfaceClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            String returnType = method.getReturnType().getName();

            int j = 0;
            String paramContent = "";
            String callParam = "";
            String paramClass = "";
            for (Class<?> paramType : method.getParameterTypes()) {
                paramContent += paramType.getName() + " args" + j + ",";
                callParam += "args" + j + ",";
                paramClass += paramType.getName() + ".class,";
                j++;
            }
            if (paramContent.length()>0) {
                paramContent = paramContent.substring(0, paramContent.length() - 1);
                callParam = "new Object[]{" + callParam.substring(0, callParam.length() - 1) + "}";
                paramClass = paramClass.substring(0, paramClass.length() - 1);
            }

            if (callParam.length() == 0) {
                callParam = "null";
            }


            String exceptionContent = "";
            for (Class<?> exceptionType : method.getExceptionTypes()) {
                exceptionContent += exceptionType.getName() + ",";
            }
            if (exceptionContent.length()>0) {
                exceptionContent = "throws " + exceptionContent.substring(0, exceptionContent.length() - 1);
            }

            content.append(forTable(1) + "public " + returnType + " " + method.getName() + "(" + paramContent + ") "
                + exceptionContent + "  {" + ENTER);
            content.append(forTable(2) + "Method declaredMethod = Class.forName("" + interfaceClass.getName()
                + "").getDeclaredMethod("" + method.getName() + """ + (paramClass.length() == 0 ? "" :
                "," + paramClass) + ");" + ENTER);
            if (!"void".equals(method.getReturnType().getName())) {
                content.append(forTable(2) + "return (" + returnType + ")");
            }
            content.append("i.invock(this,declaredMethod,"+callParam+");" + ENTER);

            content.append(forTable(1) + "}" + ENTER);
        }


        content.append("}" + ENTER);

        return content.toString();

    }


    private static String forTable(int i) {
        String str = "";
        for (int j = 0; j < i; j++) {
            str += TABLE;
        }
        return str;

    }


}
View Code

 

测试类

package com.michael.pl;

import com.michael.pl.service.LogService;
import com.michael.pl.service.impl.LogServiceImpl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestDemo {

    public static void main(String[] args) throws Exception {


        // 被代理的对象
        LogServiceImpl logServiceImpl = new LogServiceImpl();

        LogService logService = (LogService)MyProxy.newProxyInstance(TestDemo.class.getClassLoader(), LogService.class,
            new InvocationHandler() {

                @Override
                public Object invock(Object object, Method method, Object[] argss)
                    throws InvocationTargetException, IllegalAccessException {
                    System.out.println(" 代理类容!!");
                    return method.invoke(logServiceImpl, argss);
                }

            });

        logService.sayHi();
        logService.out("你好");



    }

}

 

 代码下载地址:https://files.cnblogs.com/files/MichaelPL/MyProxy.zip



 

以上是关于简单实现动态代理(Proxy)的主要内容,如果未能解决你的问题,请参考以下文章

如何用Java动态代理实现AOP

cglib实现动态代理简单使用

jdk动态代理实现

静态代理和动态代理(jdk/cglib)详解

JDK动态代理的简单理解

java Proxy InvocationHandler 动态代理实现详解