JAVA JDK动态代理原理详解

12 篇文章 1 订阅
3 篇文章 0 订阅

Java JDK动态代理原理详解:

参考文章:https://blog.csdn.net/qq_31859365/article/details/82902349

动态代理介绍

Java动态代理与静态代理相对,静态代理是在编译期就已经确定代理类和真实累的关系,并且声称代理类的,二动态代理是在运行期利用jvm的反射机制声称代理类,这里是直接生成类的字节码,然后通过类加载器将字节码文件加载到Java虚拟机并执行的一种技术。现在主流的Java动态代理有两种实现方式:一种是jdk自带的,就是我们所说的jdk动态代理,一种是开源社区的开源项目CGLIB,本文主要讲jdk代理的实现原理;
jdk动态代理的实现是在运行时,根据一组接口定义,使用Proxy、InvocationHandler等工具生成一个代理类和代理类实例;
如果还理解不了什么是动态代理,请看这里:Java代理模式详解

JDK动态代理相关API

  • Java 编译API:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  • InvocationHandler(接口):
    该接口是proxy代理实例的调用处理程序实现的一个接口,每个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编发分配到调用处理程序的invoke方法;
  • proxy类:
    该类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法;该方法有三个参数,具体参数介绍如下:
    1)、CLassLoader loader:一个ClassLoader对象,定义了由那个classloader对象生成的代理类进行加载;
    2)、Class<?> interfaces:一个interfaces对象数组,表示我们将要给我们的代理独享提供一组什么样的接口,如果我们提供了这样的一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法;
    3)、InvocationHandler h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用;

JDK动态代理过程

  • 定义一个接口:Movable,接口中有方法:move();
  • 定义一个方法调用接口InvocationHandler;
  • 定义一个方法调用接口实现类,用于调用真实对象的方法的同时添加自己的业务逻辑代码;
  • 实现接口的目标类(它要被代理);
  • 定义一个处理器TimeHandler,重载构造方法,重写invoke函数,添加自己的处理逻辑;
  • 代理逻辑实现过程编写:
    1)、定义方法字符串,用于保存方法信息;
    2)、接口方法获取;
    3)、生成实现类的对象信息
    4)、动态生成 $Proxy.java文件;
    5)、加载生成的 $Proxy.class字节码指令到内存中;
    6)、返回生成对象的引用;

代码详解

  • 定义一个接口:
//定义一个接口;
public interface Moveable {
    void move();
}
  • 实现接口的目标类
package com.example.springbootdemotest.proxy.principle;

//实现接口的目标类
public class Tank implements Moveable
{
    @Override
    public void move() {
        System.out.println("Tank Move...");
    }
}

  • 定义一个方法调用接口
package com.example.springbootdemotest.proxy.principle;

import java.lang.reflect.Method;

//定义一个方法调用接口
public interface InvocationHandler {
     void invoke(Object o, Method m);
}

  • 定义一个调用接口方法实现类
package com.example.springbootdemotest.proxy.principle;

import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler{

    private Object target;
    public TimeHandler(Object target){
        this.target = target;
    }
    @Override
    public void invoke(Object o, Method m) {
    	//此处自己编写执行真实对象方法“前”业务逻辑
        long start = System.currentTimeMillis();
        System.out.println("StartTime:"+start);
        System.out.println(o.getClass().getName());
        try {
            m.invoke(target);
        }catch (Exception e){
            e.printStackTrace();
        }
        //此处自己编写执行真实对象方法“后”业务逻辑
        long end = System.currentTimeMillis();
        System.out.println("EndTime:"+end);
        System.out.println("time:"+(end-start));
    }
}
  • 编写接口实现过程:
package com.example.springbootdemotest.proxy.principle;


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

//代理对象,
public class Proxy {
    public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
        //1、定义方法字符串,用于保存方法信息;
        String methodStr = "";
        String rt = "\r\n";
        //2、接口方法获取;
        Method[] methods = infce.getMethods();
        for (Method m : methods) {
            //生成方法信息;
            methodStr += "@Override" + rt +
                    " public void "+ m.getName()+"(){"+rt+
                    "   try{" + rt +
                    "       Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + //找到具体方法
                    "       h.invoke(this,md);" + rt +
                    "   }catch(Exception e){e.printStackTrace();}" + rt +
                    "}";
        }
        //3、生成实现类的对象信息
        String src ="package com.example.springbootdemotest.proxy.principle;"+ rt +
                "import java.lang.reflect.Method;" +rt +
                "public class $Proxy1 implements "+ infce.getName() +"{" +rt +
                "   public $Proxy1(InvocationHandler h){" +rt +
                "       this.h = h;" +rt +
                "   }" +rt +
                "   com.example.springbootdemotest.proxy.principle.InvocationHandler h;" +rt +
                    methodStr+
                "}";

        //4、动态生成$Proxy.java文件;
        //D:\software\gitRespository\springbootdemo\src\main\java\com\example\springbootdemotest\proxy\principle\$Proxy1.java
        String fileName = System.getProperty("user.dir")+"/springbootdemo-test/src/main/java/com/example/springbootdemotest/proxy/principle/$Proxy1.java";
        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //5、执行动态编译过程;
        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();

        //6、加载生成的$Proxy.class到内存中;
        //D:\software\gitRespository\springbootdemo\springbootdemo-test\src\main\java\com\example\springbootdemotest\proxy\clibPackage\MainClass.java
		//URL[] urls = new URL[]{new URL("file:"+System.getProperty("user.dir")+"/src/main/java")};
        URL[] urls = new URL[]{new URL("file:"+"D:/software/gitRespository/springbootdemo/springbootdemo-test/src/main/java")};

        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.example.springbootdemotest.proxy.principle.$Proxy1");
        System.out.println(c);
        Constructor ctr = c.getConstructor(InvocationHandler.class);
        Object m = ctr.newInstance(h);
        //m.move();
        return m;
    }

    public static void main(String[] args) throws Exception{
        Tank tank = new Tank();
        InvocationHandler h = new TimeHandler(tank);
        Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class,h);
        m.move();
    }
}
  • 执行结果如下:
class com.example.springbootdemotest.proxy.principle.$Proxy1
StartTime:1576233182481
com.example.springbootdemotest.proxy.principle.$Proxy1
Tank Move...
EndTime:1576233182482
time:1

Process finished with exit code 0

- 上述过程完整模拟jdk动态代理过程,且相关类名同jdk动态代理类名相同,如有疑问,请看:Java代理模式详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值