简单实现动态代理(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 = "\n";

    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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏克。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值