简单手写模拟JDK动态代理过程,快速阅读

下面是手写模拟了JDK动态代理的过程,几乎每行我都会注释

看之前需要了解的

1,对反射有所了解

2,对动态代理的过程有所了解

3,对阅读理解源码困难(大神就不用啦,有不足或错误的地方希望有大神指点一下)

目录结构
在这里插入图片描述
代码实现
接口类

package com.liao.dao;

public interface UserDao {
    public void query(String name);
}

目标实现类

package com.liao.dao;

public class UserDaoImpl implements UserDao {
    @Override
    public void query(String name) {
        System.out.println("name = " + name);
    }
}

模拟动态代理过程的代理类

package com.liao;

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

/**
 * 得到一个java文件
 * 编译成一个class文件
 * 通过反射得到一个对象
 * return 代理对象
 */
public class ProxyUtil {


    public static Object newProxyInstance(Object target) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        String content="";
        String packageContent="package com.liao;";//定义包名,先写死
        Class targetInfo=target.getClass().getInterfaces()[0];//获取该类的实现的第一个接口
        String targetInfoName=targetInfo.getSimpleName();//只是简单的获取接口类的名字
        String improtContent="import "+targetInfo.getName()+";";//导对应的类包
        String classContent="public class $Proxy implements "+targetInfoName+"{";
        /**
         * 下面是所要代理的类里面的内容
         */

        String fieldContent="private "+targetInfoName+" target;";//接口类的属性对象
        String construterContent="public $Proxy("+targetInfoName+" target) {"
                                    +"this.target=target;}";//代理类的构造方法
        String methodContent="";
        Method[] methods=targetInfo.getDeclaredMethods();//获取所有的私有方法
        for (Method method : methods) {//方法拼接
            String methodName=method.getName();//获取方法名
            Class returnType=method.getReturnType();//获取方法的返回类型
            Class<?>[] parameterTypes=method.getParameterTypes();//获取参数
            String argsContent = "";
            String argsNames = "";
            int i=0;
            for (Class<?> parameterType : parameterTypes) {
                String simpleName = parameterType.getSimpleName();//获取参数类型
                /**
                 * 自定义参数名字为pi
                 */
                argsContent+=simpleName+" p"+i+",";
                argsNames+="p"+i+",";
                i++;
            }
            /**
             * 把参数类型的最后一个逗号点截取掉
             */
            if(argsContent.length()>0){
                argsContent= argsContent.substring(0,argsContent.lastIndexOf(",")-1);
                argsNames= argsNames.substring(0,argsNames.lastIndexOf(",")-1);
            }
            /**
             * 拼接方法,模拟自定义输出
             */
            methodContent = "public "+returnType+" "+methodName+"("+argsContent+"){"
                    +" System.out.println(\"日志输出log...\");"//这里可以加入一些其他实际的方法
                    +"target."+methodName+"("+argsNames+");}";//调用目标方法输出
        }
        //这个content包含了一整个类的所有内容,然后存到硬盘去
        content+=packageContent+improtContent+classContent+fieldContent+construterContent+methodContent+"}";

        File file=new File("d:\\com\\liao\\$Proxy.java");
        if(!file.exists()){//如果文件不存在则新建一个
            file.createNewFile();
            System.out.println("file = " + file);
        }
        FileWriter fileWriter=new FileWriter(file);
        fileWriter.write(content);//把内容写进文件
        fileWriter.flush();//刷新文件
        fileWriter.close();//最后关闭
        /**
         * 下面是把.java文件编译为.class文件
         */
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units = fileManager.getJavaFileObjects(file);
        JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
        task.call();

        /**
         * 把.class文件加载到进程中去,并通过反射实例化对象
         */

        URL[] urls = new URL[]{new URL("file:d:\\\\")};
        URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class clazz = urlClassLoader.loadClass("com.liao.$Proxy");
        Constructor constructor = clazz.getConstructor(targetInfo);
        Object proxy = constructor.newInstance(target);//实例化代理对象,并返回出去
        return proxy;
    }
}

测试类

package com.liao.test;

import com.liao.ProxyUtil;
import com.liao.dao.UserDao;
import com.liao.dao.UserDaoImpl;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class TestProxy {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        UserDao userDao=new UserDaoImpl();
        UserDao proxy = (UserDao) ProxyUtil.newProxyInstance(userDao);
        proxy.query("华安");
    }
}

测试结果
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值