手写JDK动态代理

先看代码实现然后我们去剖析源码
1、还是需要去创建我们需要代理的代理类的接口和实现
service

public interface OrderService {
     void test() throws Throwable;
}

impl

public class OrderServiceImpl implements OrderService {
    @Override
    public void test() {
        System.out.println("【Test】");
    }
}

2、我们知道JDK动态代理是需要去实现一个InvocationHandler接口那么接下来我们就去自定义一个自己的InvocationHandler接口和创建对应的实现

/**
 * @Description:
 * @ClassName design_pattern
 * @Author: 王瑞文
 * @Date: 2021/1/16 10:50
 */
public interface MyInvocationHandler {
    /**
     *
     * @param proxy 代理类
     * @param method 代理方法(目标方法)
     * @param args  参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
}

接口实现/代理操作实现


/**
 * @Description:
 * @ClassName design_pattern
 * @Author: 王瑞文
 * @Date: 2021/1/16 10:51
 */
public class MyInvocationHandlerImpl implements MyInvocationHandler {
    //目标对象(被代理类)
    private Object target;

    public MyInvocationHandlerImpl(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("手写动态代理开始");
        Object invoke = method.invoke(target, args);//使用java的反射技术执行
        System.out.println("手写动态代理结束");
        return invoke;
    }
}

3.写自己的Proxy

public class MyProxy {
    static String rt = "\r\t";

    /**
     * @param myJavaClassLoader 自己写的类加载器
     * @param classInfo
     * @param h                 自己写的MyInvocationHandler
     * @return
     * @throws IllegalArgumentException
     */
    public static Object newProxyInstance(MyJavaClassLoader myJavaClassLoader, Class classInfo, MyInvocationHandler h)//修改成自己写的MyInvocationHandler
            throws IllegalArgumentException {
        try {


            //1.拼接JAVA代理类的源代码
            Method[] methods = classInfo.getMethods();
            String proxyClass = "package 纯手写JDK动态代理;" + rt  //包名
                    + "import java.lang.reflect.Method;" + rt
                    + "import 纯手写JDK动态代理.MyInvocationHandler;" + rt   //我们自己的handler
                    + "public class $Proxy0 implements " + classInfo.getName() + "{" + rt
                    + "MyInvocationHandler h;" + rt
                    + "public $Proxy0(MyInvocationHandler h)" + "{" + rt
                    + "this.h= h;" + rt + "}"
                    + getMethodString(methods, classInfo) + rt + "}";
            // 2. 将代理类源码文件写入硬盘中
            String filename = "d:/test/$Proxy0.java";
            File f = new File(filename);
            FileWriter fw = new FileWriter(f);
            fw.write(proxyClass);
            fw.flush();
            fw.close();
            //3.将源代码去编译成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            Iterable units = fileMgr.getJavaFileObjects(filename);
            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();
            //4.使用ClassLoader加载到内存中
            Class proxy0Class = myJavaClassLoader.findClass("$Proxy0");//调用提前写好的自己的类加载器
            //5.指明初始化有参数构造函数
            Constructor constructor = proxy0Class.getConstructor(MyInvocationHandler.class);
            Object o = constructor.newInstance(h);
            return o;
        } catch (Exception e) {
            System.out.println("出现异常");
        }
        return null;

    }

    public static String getMethodString(Method[] methods, Class intf) {
        String proxyMe = "";
        for (Method method : methods) {
            proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt
                    + "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName()
                    + "\",new Class[]{});" + rt
                    + "this.h.invoke(this,md,null);" + rt + "}" + rt;

        }
        return proxyMe;
    }
}

4.自定义类加载器去加载我们自定义的MyProxy生成的$Proxy0文件

public class MyJavaClassLoader extends ClassLoader {

    private File classPathFile;

    public MyJavaClassLoader() {
//        String classPath=JavaClassLoader.class.getResource("").getPath();
        String classPath = "D:\\test";
        this.classPathFile = new File(classPath);
    }

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        String className = MyJavaClassLoader.class.getPackage().getName() + "." + name;
        if (classPathFile != null) {
            File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
            if (classFile.exists()) {

                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

5.测试

public class Test001 {
    public static void main(String[] args) throws NoSuchMethodException {
        OrderService orderService = (OrderService) MyProxy.newProxyInstance(new MyJavaClassLoader(), OrderService.class, new MyInvocationHandlerImpl(new OrderServiceImpl()));
        try {
            orderService.test();
        } catch (Throwable throwable) {
        }
    }
}

接下来说一下实现的思路:
1、使用JAVA语言组装$proxy0源码,在上边MyProxy中可以看出来我们使用的时字符串去拼接一个代理类的源代码,使用java的反射技术获取该接口下面所有方法
2、将 $proxy.java代理类的源代码编译成 $proxy0.class文件 JavaCompiler技术,类似于命令行输入javac
3、使用ClassLoader把class文件加载到内存中去

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值