jdk动态代理源码分析

news2024/11/23 15:15:44

jdk动态代理源码分析

  • 前言
  • 动态代理----demo 案例
  • jdk动态代理源码
    • 创建代理对象
    • 获取类
    • 把二进制流生成文件
  • jdk 动态代理的原理

前言

上一篇中我们知道动态代理的使用, Javase 专题之 静态代理和动态代理
我们只知道其中的使用,但是原理是什么? 不明白原理只知皮毛不是我们的目的,今天看看jdk如何实现的动态代理,我们如何简单实现一个动态代理?

动态代理----demo 案例

接口

public interface Factory {
    public String create(String name);
}

实现类:

public class NicekFactory implements Factory
{
    public String create(String name) {
        System.out.println("生产"+name);
        return name;
    }
}

获取代理对象

public class ProxyFactory {
    public Object getProxy(Class[] cls,Object object){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(), cls, new MyInvocationHandler(object));
    }

}

InvocationHandler

public class MyInvocationHandler implements InvocationHandler {

    private Object object;

    public MyInvocationHandler(Object object) {
        this.object = object;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("统一颜色");
        Object invoke = method.invoke(object, args);
        System.out.println("统一包装");
        return invoke;
    }
}

使用

public class Application {
    public static void main(String[] args) {
        NicekFactory nicekFactory = new NicekFactory();

        Factory proxy = (Factory)new ProxyFactory().getProxy(new Class[]{Factory.class},nicekFactory );
        proxy.create("nike");
    }
}

代理其实就是为了对自己的实现类进行增强,我们看到最后主要是靠InvocationHandler 的invoke 方法处理
因为代理类最后都会走这个invoke 方法

到这列可以进行运行,我们思考发现:

1.首先要定义接口,我们知道spring cglib 代理是不需要接口的
2.接口需要实现类,我们知道使用的mybatis框架中 mapper是不需要进行写实现的又是如何做到的
3.最后结论: 我们给接口写一个实现,jdk根据我们的实现生成代理类,运行的时候使用代理类,对实现做一个增强
4.这样我们需要思考: 动态代理生成的代理对象是啥样的?结构又是啥样的?

jdk动态代理源码

带着上面的几个问题 我们先分析下动态代理的源码?????

创建代理对象

Proxy.newProxyInstance(this.getClass().getClassLoader(), cls, new MyInvocationHandler(object));
 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
		
        /*
        * 上面都是检查,下面获取代理类,此时的代理类加载到内存中
        * 1.获取代理对象的Class
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // 2. 根据Class获取构造函数,进行对象实例化
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

获取类

 Class<?> cl = getProxyClass0(loader, intfs);

上面的代码核心一块:
java.lang.reflect.Proxy.ProxyClassFactory#apply

省略。。。。。。。。
/*
             * Generate the specified proxy class.
             * 生成 代理类二进制流的数据
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
            //加载到内存中。。。。
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {

把二进制流生成文件

生成代码


    public static void main(String[] args) throws Exception {
        /*
         * Generate the specified proxy class.
         */
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                "com.sum.proxy.$Proxy0", new Class[]{Factory.class}, 17);
        String path = ClassLoader.getSystemResource("aa.txt").getPath();
        FileOutputStream outputStream = new FileOutputStream("/Users/project/examples/Proxy/src/main/resources/"+"aa.class");
        System.out.println(path);
        outputStream.write(proxyClassFile);
        outputStream.flush();
        outputStream.close();
    }

生成代码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sum.proxy;

import com.wfg.dynamic.Factory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Factory {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String create(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.wfg.dynamic.Factory").getMethod("create", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

当我们使用代理类调用方法的时候 就是这个

 public final String create(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

super.h 就是我们传入的 InvocationHandler 因此就执行下面的invoke 方法
在这里插入图片描述

jdk 动态代理的原理

  1. 拿到被代理对象的引用,然后获取它的接口
  2. jdk代理重新生成一个类,同时实现我们给的代理所实现的接口
  3. 把被代理对象的引用也拿到
  4. 重新动态生成一个class字节码
  5. 然后编译

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/610480.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python在原图上继续画的SEO

Python在原图上继续画的SEO Python是一种高级的多范式编程语言&#xff0c;它使用简单、易于阅读的语法以及丰富和强大的数据结构使其成为工程师的首选。Python已经成为了一种非常流行的编程语言&#xff0c;它用于多种应用领域&#xff0c;包括Web开发、数据科学、机器学习、…

区间预测 | MATLAB实现基于QRCNN-LSTM卷积长短期记忆神经网络多变量时间序列区间预测

区间预测 | MATLAB实现基于QRCNN-LSTM卷积长短期记忆神经网络多变量时间序列区间预测 目录 区间预测 | MATLAB实现基于QRCNN-LSTM卷积长短期记忆神经网络多变量时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRCNN-LSTM卷积神经…

注解、原生Spring、SchemaBased三种方式实现AOP【附详细案例】

目录 一、注解配置AOP 1. 开启注解支持 2. 在类和方法加入注解 3. 测试 4. 为一个类下的所有方法统一配置切点 二、原生Spring实现AOP 1. 引入依赖 2. 编写SpringAOP通知类 3. 编写配置类bean2.xml 4 测试 三、SchemaBased实现AOP 1. 配置切面 2. 测试 往期专栏…

音视频技术开发周刊 | 296

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 22字声明、近400名专家签署、AI教父Hinton与OpenAI CEO领头预警&#xff1a;AI可能灭绝人类&#xff01; 这份声明一经发布&#xff0c;便迅速得到了多伦多大学计算机科学…

基于zookeeper的kafka中间件

一、Zookeeper 概述 1、Zookeeper 定义 Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 2、Zookeeper 工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理…

昨天,小灰做了人生的第一次直播!

熟悉小灰的朋友们都知道&#xff0c;小灰是一个非常腼腆的人。虽然我比较擅长写东西&#xff0c;但完全不擅长口头表达&#xff0c;在公开场合讲话很容易紧张。 因此&#xff0c;对于网上直播&#xff0c;小灰在以前完全不敢想象。 但是&#xff0c;人终究需要成长的。就在昨天…

Disco Diffusion 快速入门

Disco Diffusion 快速入门 简介快速开始进阶使用修改prompt给定指导图像修改基础参数运行参数设置运行建议模型设置参数详情 简介 Disco Diffusion&#xff08;DD&#xff09;是一个CLIP指导的AI图像生成技术&#xff0c;简单来说&#xff0c;Diffusion是一个对图像不断去噪的…

路径规划 | 图解RRT-Connect算法(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 RRT-Connect基本原理2 RRT-Connect vs. RRT3 ROS C算法实现4 Python算法实现5 Matlab算法实现 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全局规划(图搜索、采样法、智能算法等)…

chatgpt赋能python:Python实现奇数位偶数位互换的方法

Python实现奇数位偶数位互换的方法 Python是一种高级的、面向对象的编程语言&#xff0c;在当今的编程领域中具有广泛的应用。它被用于数据分析、机器学习、Web开发等众多领域&#xff0c;其简洁的语法和强大的库被开发者们广泛使用。本文将介绍Python中奇数位偶数位互换的方法…

驱动开发:内核实现SSDT挂钩与摘钩

在前面的文章《驱动开发&#xff1a;内核解析PE结构导出表》中我们封装了两个函数KernelMapFile()函数可用来读取内核文件&#xff0c;GetAddressFromFunction()函数可用来在导出表中寻找指定函数的导出地址&#xff0c;本章将以此为基础实现对特定SSDT函数的Hook挂钩操作&…

【Django 网页Web开发】07. 快捷的表单生成 Form与MoudleForm(保姆级图文)

目录 注意 正规写法是 ModelForm&#xff0c;下面文章我多实现效果url.py新建3个html文件数据库连接model.py 数据表1. 原始方法view.pytestOrgion.html 2. Form方法view.pytestForm.html 3. MoudleForm方法给字段设置样式面向对象的思路&#xff0c;批量添加样式错误信息的显示…

ASIC-WORLD Verilog(10)编写测试脚本Testbench的艺术

写在前面 在自己准备写一些简单的verilog教程之前&#xff0c;参考了许多资料----Asic-World网站的这套verilog教程即是其一。这套教程写得极好&#xff0c;奈何没有中文&#xff0c;在下只好斗胆翻译过来&#xff08;加了自己的理解&#xff09;分享给大家。 这是网站原文&…

干货!来自北大、KAUST、斯坦福、达摩院的大模型前沿动态:表格推理、代码生成、MiniGPT-4、生成式推理...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; ChatGPT的发布使得国内外众多的研究机构掀起了一股AI热潮&#xff0c;而这也进一步推动了人们对大语言模型的深入研究。2023年4月26日&#xff0c;AI TIME举办的大模型专场四活动邀请了阿里巴巴达摩院NLP研究员…

在 IDEA 中配置 JavaFX 11

因为从 Java8/openjdk 之后&#xff0c;javafx 从 jdk 中移除&#xff0c;如果进行 JavaFX 开发需要在 module 中添加 lib&#xff0c;并对 IDE 进行配置&#xff0c;确保 jdk 可以与 javafx 正常调用。 javafx 下载路径&#xff0c;主页网址&#xff1a;https://openjfx.io/ …

开发实践|程序员是如何刷抖音、玩快手、看头条进行赚米的?

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; “ 花开堪折直须折&#xff0c;莫待无花空折枝。 ” 作者主页&#xff1a;[ https://www.weiyigeek.top ] 博客&…

【计算机组成原理与体系结构】数据的表示与运算

目录 一、进位计数制 二、信息编码 三、定点数数据表示 四、校验码 五、定点数补码加减运算 六、标志位的生成 七、定点数的移位运算 八、定点数的乘除运算 九、浮点数的表示 十、浮点数的运算 一、进位计数制 整数部分&#xff1a; 二进制、八进制、十六进制 --…

穿越认知峡谷

十年前&#xff0c;2013 年的这个时候&#xff0c;“互联网思维”在国内大火。我没有认真研究过这件事的来龙去脉&#xff0c;不过印象里 2012 年底《罗辑思维》视频栏目的开播&#xff0c;以及差不多同时小米手机的爆发&#xff0c;对“互联网思维”的大流行应该是起了重要的推…

【ABAP】数据类型(一)「数据类型概要及分类」

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…

Nginx正则表达式、location、rewrite

目录 一、常用的Nginx正则表达式 二&#xff1a;localtion 1、location 分类 2、 location 常用的匹配规则 3、location 优先级 4、 location 示例 5、优先级总结 6、实际网站使用中&#xff0c;至少有三个匹配规则定义 &#xff08;1&#xff09;第一个必选规则 &…

深入理解设计原则之接口隔离原则(ISP)【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 LSP&#xff1a;接口隔离原则 系列文章目录1、接口隔离原则的定义和解读2、案例解读3、如何判断一个接口是否符合接口隔离原则&#xff1f;小结 1、接口隔离原则的定义和…