互联网架构-精讲设计模式-006:纯手写动态代理模式

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();
    }
}

结果:
在这里插入图片描述

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 JDK动态代理源码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值