欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式

程序员文章站 2022-06-15 11:33:42
...

1 纯手写JDK动态代理思路分析

课程内容:
1、回顾JDK动态代理与CGLib代理区别
2、JDK动态代理大致原理回顾
3、纯手写Jdk动态代理的思路
4、JavaCompiler编译源文件技术
5、自定义ClassLoader读取class文件到内存中

CGLIB与JDK动态代理区别是什么?
jdk动态代理:被代理类必须实现接口,实现方式,java反射执行
cligb动态代理:使用继承被代理类,继承方式,ASM生成子类

纯手写JDK动态代理 原理思路
1.创建代理类$Proxy0源代码文件实现被代理的接口,使用java反射技术获取该接口下面所有方法;
2.使用JavaCompiler技术编译该$Proxy0文件编译成$Proxy0.class文件;
3.使用ClassLoader将该$Proxy0.class加入到当前JVM内存中

2 简单版本实现Jdk动态代理

MyExtJdkInvocationHandler

public interface MyExtJdkInvocationHandler {

    /**
     *
     * @param proxy 代理类
     * @param method 目标方法
     * @param args 参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
}

MyJdkInvocationHandler

public class MyJdkInvocationHandler implements MyExtJdkInvocationHandler {

    /**
     * 目标对象 被代理类 真实访问的类的对象
     */
    private Object target;

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

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

OrderService

public interface OrderService {

    public void order() throws Throwable;
}

OrderServiceImpl

public class OrderServiceImpl implements OrderService {

    @Override
    public void order() {
        System.out.println("数据库订单执行操作..");
    }
}

$Proxy0(假设存在)

public class $Proxy0 implements OrderService {

    private MyExtJdkInvocationHandler h;

    public $Proxy0(MyExtJdkInvocationHandler h){
        this.h = h;
    }

    @Override
    public void order() throws Throwable {
        // 如何获取到真实目标方法?
        Method orderMethod = OrderService.class.getMethod("order", new Class[]{});
        this.h.invoke(this, orderMethod, null);
    }
}

测试类

public class Test001 {
    public static void main(String[] args) throws Throwable {
        OrderService orderService = new $Proxy0(new MyJdkInvocationHandler(new OrderServiceImpl()));
        orderService.order();
    }
}

结果:
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式

3 完全纯手写JDK动态代理01

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

    public static Object newProxyInstance(JavaClassLoader javaClassLoader,
                                          Class<?> classInfo,
                                          MyExtJdkInvocationHandler h) {
        try {
            // 1.拼接代码类的源代码
            Method[] methods = classInfo.getMethods();
            String proxyClass = "package com.mayikt.extProxy.ext.proxy;" + rt
                    + "import java.lang.reflect.Method;" + rt
                    + "import com.mayikt.extProxy.ext.proxy.MyExtJdkInvocationHandler;" + rt
                    + "public class $Proxy0 implements " + classInfo.getName() + "{" + rt
                    + "MyExtJdkInvocationHandler h;" + rt
                    + "public $Proxy0(MyExtJdkInvocationHandler h)" + "{" + rt
                    + "this.h= h;" + rt + "}"
                    + getMethodString(methods, classInfo) + rt + "}";
            // 2.写入到本地文件中..
            String filename = "d:/code/$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<?> $Proxy0 = javaClassLoader.findClass("$Proxy0");
            // 5.指明初始化有参数构造函数
            Constructor<?> constructor = $Proxy0.getConstructor(MyExtJdkInvocationHandler.class);
            Object o = constructor.newInstance(h);
            return o;
        }catch (Exception e){
            e.printStackTrace();
        }
        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;
    }

    public static void main(String[] args) {
        newProxyInstance(null, OrderService.class, null);// 测试在指定文件夹生成代理类文件
    }

}
public class Test001 {
    public static void main(String[] args) throws Throwable {
        OrderService orderService = (OrderService) MyProxy.newProxyInstance(new JavaClassLoader(), OrderService.class, new MyJdkInvocationHandler(new OrderServiceImpl()));
        orderService.order();
    }
}

4 完全纯手写JDK动态代理02

JavaClassLoader

public class JavaClassLoader extends ClassLoader {

    private File classPathFile;

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

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        String className= JavaClassLoader.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期-互联网架构-006:纯手动态代理模式

5 JDK动态代理源码分析

蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式