手写jdk动态代理

本文详细介绍了Java动态代理的实现过程,包括手动创建代理类、动态编译Java源文件、加载class到JVM以及使用反射创建代理对象。通过示例展示了如何从静态代理转换为动态代理,引入了自定义InvocationHandler接口来执行代理逻辑。最后,文章演示了如何修改代码以适应动态生成代理类的需求。
摘要由CSDN通过智能技术生成

jdk动态代理原理

1.手写动态代理

场景:

1.生成一个java文件 2.动态编译一个.class文件 3.拿到这个class文件后,我们通过反射获取一个对象

target对象-----通过代理生成java文件-------编译成class文件------调用反射方式class.newIstance-----------------得到代理对象proxy

public class StaticProxy implements MyService {
    private MyService target;

     public StaticProxy(MyService target){
         this.target = target;
     }

    @Override
    public void test01() {
        System.out.println("proxy print log for test01");
        target.test01();
    }

    @Override
    public void test02(String s) {
        System.out.println("proxy print log for test02");
        target.test02(s);
    }
}

上面是静态代理

1.拼接字符串,将上面的代码以字符串的形式拼接出来并写入到磁盘文件上

2.编译java文件生成class文件

3.加载class文件到jvm内存中,得到一个class对象

4.调用反射方法得到对象

代码如下:

public class ProxyUtil {

    public static Object newInstance(Object target){
        Object proxy = null;
        // 拼接字符串java文件
        Class targetInf = target.getClass().getInterfaces()[0];
        // 获取所有的方法
        Method[] declaredMethods = targetInf.getDeclaredMethods();
        // \r\n
        String line = System.lineSeparator();
        String tab = "\t";
        // 获取类的名称 System.class System
        String infName = targetInf.getSimpleName();
        String context = "";
        // package com;
        String packageContext = "package com.hxy.proxy;" + line;
        // import com.MyService;
        String importContext = "import "+ targetInf.getName() + ";" +line;
        String clazzFirstLineContext = "public class $Proxy implements " +infName + "{" +line;
        String filedContent = tab + "private " + infName + " target;" + line;
        String constructorContent = tab + "public $Proxy (" + infName + " target){" + line
                + tab + tab + "this.target =target;"
                + line + tab + "}" + line;
        String methodContent = "";
        for (Method method : declaredMethods) {
            String returnTypeName = method.getReturnType().getSimpleName();
            String methodName = method.getName();
            // Sting.class String.class
            Class args[] = method.getParameterTypes();
            String argsContent = "";
            String paramsContent = "";
            int flag = 0;
            for (Class arg : args) {
                String temp = arg.getSimpleName();
                //String
                //String p0,Sting p1,
                argsContent += temp + " p" + flag + ",";
                paramsContent += "p" + flag + ",";
                flag++;
            }
            if (argsContent.length() > 0) {
                argsContent = argsContent.substring(0, argsContent.lastIndexOf(",") - 1);
                paramsContent = paramsContent.substring(0, paramsContent.lastIndexOf(",") - 1);
            }

            methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {" + line
                    + tab + tab + "System.out.println(\"proxy print log for " + methodName + "\");" + line
                    + tab + tab + "target." + methodName + "(" + paramsContent + ");" + line
                    + tab + "}" + line;

        }
        // 以上是拼接java文件
        context = packageContext + importContext + clazzFirstLineContext + filedContent + constructorContent + methodContent + "}";
        // 生成java文件
        File file = new File("E:\\com\\hxy\\proxy\\$Proxy.java");
        try {
            if(!file.exists()){
                file.createNewFile();
             }
            FileWriter fw = new FileWriter(file);
            fw.write(context);
            fw.flush();
            fw.close();

            // 开始编译java
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
            JavaCompiler.CompilationTask task = compiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
            task.call();
            standardFileManager.close();
            // 加载class
            URL[] urls = new URL[]{new URL("file:E:\\\\")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class<?> clazz = urlClassLoader.loadClass("com.hxy.proxy.$Proxy");
            System.out.println(targetInf);
            // 通过构造方法去创建对象
            Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
            Constructor<?> declaredConstructor = declaredConstructors[0];
            proxy = declaredConstructor.newInstance(target);
            // 也可以用推断构造方法去生成对象
        } catch (Exception e) {
            e.printStackTrace();
        }
        return proxy;
    }

    public static void main(String[] args) {
        MyServiceImpl target = new MyServiceImpl();
        MyService o = (MyService) ProxyUtil.newInstance(target);
        o.test01();
        o.test02("test02");
    }

在这里插入图片描述

打开java文件可以看到如下:
在这里插入图片描述

运行程序可以看到:

在这里插入图片描述

以上就是通过先生成java文件在把java文件编译成class文件,再通过把class对象加载到内存中通过确定的构造方法去创建对象

如果想动态执行 代理逻辑需要代持接口

新增接口CoustomInvocationHandler

public interface CoustomInvocationHandler {
    public Object invoke(Method method);
}

实现类如下:

public class TestCustomHandler implements CoustomInvocationHandler {
    Object target;
    public TestCustomHandler(Object target){
        this.target=target;
    }

    @Override
    public Object invoke(Method method) {
        try {
            System.out.println("----------------");
            return  method.invoke(target);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}

需要修改上面的ProxyUtil类主要是生成java文件的方法
生成java文件相关方法改为

public static Object newInstance(Class targetInf, CoustomInvocationHandler h){
    Object proxy=null;
    //String handlerName = CoustomInvocationHandler.class.
    Method methods[] =targetInf.getDeclaredMethods();
    String line="\n";
    String tab ="\t";
    String infName = targetInf.getSimpleName();
    String content ="";
    String packageContent = "package com.hxy;"+line;
    String importContent = "import "+targetInf.getName()+";"+line
                         +"import com.luban.dao.CoustomInvocationHandler;"+line
                         +"import java.lang.Exception;" +line
                         +"import java.lang.reflect.Method;"+line;
    String clazzFirstLineContent = "public class $Proxy implements "+infName+"{"+line;
    String filedContent  =tab+"private CoustomInvocationHandler h;"+line;
    String constructorContent =tab+"public $Proxy (CoustomInvocationHandler h){" +line
                              +tab+tab+"this.h = h;"
                              +line+tab+"}"+line;
    String methodContent = "";
    for (Method method : methods) {
        String returnTypeName = method.getReturnType().getSimpleName();
        String methodName =method.getName();
        // Sting.class String.class
        Class args[] = method.getParameterTypes();
        String argsContent = "";
        String paramsContent="";
        int flag =0;
        for (Class arg : args) {
            String temp = arg.getSimpleName();
            //String
            //String p0,Sting p1,
            argsContent+=temp+" p"+flag+",";
            paramsContent+="p"+flag+",";
            flag++;
        }
        if (argsContent.length()>0){
            argsContent=argsContent.substring(0,argsContent.lastIndexOf(",")-1);
            paramsContent=paramsContent.substring(0,paramsContent.lastIndexOf(",")-1);
        }

        methodContent+=tab+"public "+returnTypeName+" "+methodName+"("+argsContent+")throws Exception {"+line
                       +tab+tab+"Method method = Class.forName(\""+targetInf.getName()+"\").getDeclaredMethod(\""+methodName+"\");"+line;

        if(method.getReturnType().equals(Void.TYPE)){
            methodContent +=  tab+tab+ "h.invoke(method);"+line;
        }else{
            methodContent += tab+tab+"return ("+returnTypeName+")h.invoke(method);"+line;
        }
        methodContent+=tab+"}"+line;
    }

    content=packageContent+importContent+clazzFirstLineContent+filedContent+constructorContent+methodContent+"}";

    File file =new File("E:\\com\\hxy\\$Proxy.java");

效果如下:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值