我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JDK动态代理过程原理及手写实现详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JDK动态代理过程原理及手写实现详解

JDK动态代理的过程

JDK动态代理采用字节重组,重新生成对象来替代原始对象,以达到动态代理的目的。

JDK中有一个规范,在ClassPath下只要是$开头的.class文件,一般都是自动生成的。

要实现JDK动态代理生成对象,首先得弄清楚JDK动态代理的过程。

1.获取被代理对象的引用,并且使用反射获取它的所有接口。

2.JDK动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口。

3.动态生成Java代码,新添加的业务逻辑方法由一定的逻辑代码调用。

4.编译新生成的Java代码(.class文件)。

5.重新加载到VM中运行。

手写实现JDK动态代理

JDK动态代理功能非常强大, 接下来就模仿JDK动态代理实现一个属于自己的动态代理。

创建MyInvocationHandler接口

参考JDK动态代理的InvocationHandler 接口,创建属于自己的MyInvocationHandler接口

public interface MyInvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

创建MyClassLoader类加载器

public class MyClassLoader extends ClassLoader {
    private File classPathFile;
    public MyClassLoader() {
        String classPath = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }
    @Override
    protected Class<?> findClass(String name) {
        String className = MyClassLoader.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();
                }
            }
        }
        return null;
    }
}

创建代理类

创建的代理类是整个JDK动态代理的核心

public class MyProxy {
    // 回车、换行符
    public static final String ln = "\r\n";
    
    public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler invocationHandler) {
        try {
            // 动态生成源代码.java文件
            String sourceCode = generateSourceCode(interfaces);
            // 将源代码写入到磁盘中
            String filePath = MyProxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(sourceCode);
            fw.flush();
            fw.close();
            // 把生成的.java文件编译成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manage.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
            task.call();
            manage.close();
            // 编译生成的.class文件加载到JVM中来
            Class proxyClass = classLoader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
            //删除生成的.java文件
            f.delete();
            // 返回字节码重组以后的新的代理对象
            return c.newInstance(invocationHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    private static String generateSourceCode(Class<?>[] interfaces) {
        StringBuffer sb = new StringBuffer();
        sb.append(MyProxy.class.getPackage() + ";" + ln);
        sb.append("import " + interfaces[0].getName() + ";" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
        sb.append("MyInvocationHandler invocationHandler;" + ln);
        sb.append("public $Proxy0(MyInvocationHandler invocationHandler) { " + ln);
        sb.append("this.invocationHandler = invocationHandler;");
        sb.append("}" + ln);
        for (Method m : interfaces[0].getMethods()) {
            Class<?>[] params = m.getParameterTypes();
            StringBuffer paramNames = new StringBuffer();
            StringBuffer paramValues = new StringBuffer();
            StringBuffer paramClasses = new StringBuffer();
            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                String paramName = toLowerFirstCase(clazz.getSimpleName());
                paramNames.append(type + " " + paramName);
                paramValues.append(paramName);
                paramClasses.append(clazz.getName() + ".class");
                if (i > 0 && i < params.length - 1) {
                    paramNames.append(",");
                    paramClasses.append(",");
                    paramValues.append(",");
                }
            }
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames + ") {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses + "});" + ln);
            sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + getCaseCode("this.invocationHandler.invoke(this,m,new Object[]{" + paramClasses + "})", m.getReturnType()) + ";" + ln);
            sb.append("}catch(Error ex) { }");
            sb.append("catch(Throwable e){" + ln);
            sb.append("throw new UndeclaredThrowableException(e);" + ln);
            sb.append("}");
            sb.append(getReturnEmptyCode(m.getReturnType()));
            sb.append("}");
        }
        sb.append("}" + ln);
        return sb.toString();
    }
    
    private static Map<Class, Class> mappings = new HashMap<Class, Class>();
    
    static {
        mappings.put(int.class, Integer.class);
        mappings.put(Integer.class, Integer.class);
        mappings.put(double.class, Double.class);
        mappings.put(Double.class, Double.class);
    }
    private static String getReturnEmptyCode(Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            if (returnClass.equals(int.class) || returnClass.equals(Integer.class)) {
                return "return 0;";
            } else if (returnClass.equals(double.class) || returnClass.equals(Double.class)) {
                return "return 0.0;";
            } else {
                return "return 0;";
            }
        } else if (returnClass == void.class) {
            return "";
        } else {
            return "return null;";
        }
    }
    
    private static String getCaseCode(String code, Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            // ((java.lang.Double) this.invocationHandler.invoke(this, m, new Object[]{})).doubleValue();
            String re = "((" + mappings.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName().toLowerCase() + "Value()";
            return re;
        }
        return code;
    }
    
    private static boolean hasReturnValue(Class<?> clazz) {
        return clazz != void.class;
    }
    
    private static String toLowerFirstCase(String class="lazy" data-src) {
        char[] chars = class="lazy" data-src.toCharArray();
        if (chars[0] >= 'A' && chars[0] <= 'Z') {
            chars[0] += 32;
        }
        return String.valueOf(chars);
    }
    
    private static String toUpperFirstCase(String class="lazy" data-src) {
        char[] chars = class="lazy" data-src.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] -= 32;
        }
        return String.valueOf(chars);
    }
}

使用自定义动态代理类

创建接口

public interface IUser {
    void shopping();
    Double expenses();
}

创建被代理接口

public class User implements IUser {
    @Override
    public void shopping() {
        System.out.println("user shopping....");
    }
    @Override
    public Double expenses() {
        return 50.5;
    }
}

创建代理接口

public class UseProxy implements MyInvocationHandler {
    private Object target;
    public Object myJDKProxy(Object target){
        this.target = target;
        Class&lt;?&gt; clazz =  target.getClass();
        return MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理user,执行shopping()开始...");
        Object result = method.invoke(this.target, args);
        System.out.println("代理user,执行shopping()结束...");
        return result;
    }
}

客户端调用

    public static void main(String[] args) {
        UseProxy useProxy = new UseProxy();
        IUser user = (IUser) useProxy.myJDKProxy(new User());
        user.shopping();
        System.out.println(user.expenses());
    }

执行结果

代理user,执行shopping()开始...
user shopping....
代理user,执行shopping()结束...
--------------------------------
代理user,执行shopping()开始...
代理user,执行shopping()结束...
--------------------------------
50.5

生成源代码

查看生产的Java文件源代码

package cn.ybzy.demo.proxy.proxy;
import cn.ybzy.demo.proxy.client.IUser;
import java.lang.reflect.*;
public class $Proxy0 implements cn.ybzy.demo.proxy.client.IUser{
MyInvocationHandler invocationHandler;
public $Proxy0(MyInvocationHandler invocationHandler) { 
this.invocationHandler = invocationHandler;}
public java.lang.Double expenses() {
try{
Method m = cn.ybzy.demo.proxy.client.IUser.class.getMethod("expenses",new Class[]{});
return ((java.lang.Double)this.invocationHandler.invoke(this,m,new Object[]{})).doubleValue();
}catch(Error ex) { }catch(Throwable e){
throw new UndeclaredThrowableException(e);
}return 0.0;}public void shopping() {
try{
Method m = cn.ybzy.demo.proxy.client.IUser.class.getMethod("shopping",new Class[]{});
this.invocationHandler.invoke(this,m,new Object[]{});
}catch(Error ex) { }catch(Throwable e){
throw new UndeclaredThrowableException(e);
}}}

以上就是JDK动态代理过程原理及手写实现详解的详细内容,更多关于JDK动态代理过程的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JDK动态代理过程原理及手写实现详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

纯手写实现JDK动态代理

作者:张丰哲原文:https://www.jianshu.com/p/58759fef38b8前言在Java领域,动态代理应用非常广泛,特别是流行的Spring/MyBatis等框架。JDK本身是有实现动态代理技术的,不过要求被代理的类必须
2023-06-02

基于jdk动态代理和cglib动态代理实现及区别说明

这篇文章主要介绍了基于jdk动态代理和cglib动态代理实现及区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-05-19

在Java中实现JDK动态代理的原理是什么

在Java中实现JDK动态代理的原理是什么?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、什么是代理?代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对
2023-05-31

(手写)PCA原理及其Python实现图文详解

目录1、背景2、样本均值和样本方差矩阵3、PCA3.1 最大投影方差3.2 最小重构距离4、Python实现总结1、背景 为什么需要降维呢?因为数据个数 N 和每个数据的维度 p 不满足 N >> p,造成了模型结果的“过拟合”。有两种方法
2022-06-02

一文详解手动实现Recoil状态管理基本原理

这篇文章主要为大家介绍了一文详解手动实现Recoil状态管理基本原理实例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-19

Java动态代理的原理及实现方法是什么

本篇内容主要讲解“Java动态代理的原理及实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java动态代理的原理及实现方法是什么”吧!代理是指:某些场景下对象会找一个代理对象,来辅助
2023-07-02

深入理解java动态代理的两种实现方式(JDK/Cglib)

什么是代理模式?代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作。在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能。为什么要使用代理模式?通过代理模式可以实现对
2023-05-31

解读jdk动态代理为什么必须实现接口

这篇文章主要介绍了解读jdk动态代理为什么必须实现接口问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-17

Nest.js之依赖注入原理及实现过程详解

这篇文章主要为大家介绍了Nest.js之依赖注入原理及实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-12

android:照片涂画功能实现过程及原理详解

这个功能可以帮你实现,在图片上进行随意的涂抹,可以用于SNS产品。 绘图本身很简单,但是要实现在图片上指定的部分精确(位置,缩放)的绘图,就有点麻烦了。 下面讲讲实现过程及原理: UI构图这个UI,看似简单,还是有点复杂的,下面需要一个底图
2022-06-06

Java动态代理四种实现方式详解

代理模式也是一种非常常见的设计模式。了解Spring框架的都知道,Spring AOP 使用的就是动态代理模式。今天就来系统的重温一遍代
Java动态代理四种实现方式详解
2022-06-07

详解B+树的原理及实现Python代码

B+树是自平衡树的高级形式,其中所有值都存在于叶级中。B+树所有叶子都处于同一水平,每个节点的子节点数量≥2。B+树与B树的区别是各节点在B树上不是相互连接,而在B+树上是相互连接的。B+树多级索引结构图B+树搜索规则1、从根节点开始
详解B+树的原理及实现Python代码
2024-01-24

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录