【JDK动态代理】及【CGLib动态代理】:Java的两种动态代理方式

Java的两种动态代理方式

  • 动态代理是什么?
  • JDK动态代理
  • CGLib动态代理
      • CGLib 底层原理
      • CGLib 实现步骤
  • 两者区别
  • Spring AOP原理--动态代理

动态代理是什么?

    动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。
    在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。

代理类在程序运行期间,创建的代理对象称之为动态代理对象。

    这种情况下,创建的代理对象,并不是事先在Java代码中定义好的。而是在运行期间,根据我们在动态代理对象中的“指示”,动态生成的。也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象。动态代理可以对被代理对象的方法进行功能增强。有了动态代理的技术,那么就可以在不修改方法源码的情况下,增强被代理对象的方法的功能,在方法执行前后做任何你想做的事情。

创建代理对象的两个方法:

JDK动态代理

Proxy.newProxyInstance(三个参数);

CGLib动态代理

Enhancer.create(两个参数);

JDK动态代理

🔺基于接口的动态代理
🔺提供者:JDK
🔺使用JDK官方的Proxy类创建代理对象
🔺注意:代理的目标对象必须实现接口

public class LogJdkProxy {
    /**
     * 生成对象的代理对象,对被代理对象进行所有方法日志增强
     * 参数:原始对象
     * 返回值:被代理的对象
     * JDK 动态代理
     *  基于接口的动态代理
     *  被代理类必须实现接口
     *  JDK提供的
     */
    public static Object getObject(final Object obj){
        /**
         * 创建对象的代理对象
         * 参数一:类加载器
         * 参数二:对象的接口
         * 参数三:调用处理器,代理对象中的方法被调用,都会在执行方法。对所有被代理对象的方法进行拦截
         */
        Object proxyInstance = Proxy.newProxyInstance(obj.getClass().getClassLoader()
                , obj.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法执行前
                long startTime = System.currentTimeMillis();

                Object result = method.invoke(obj, args);//执行方法的调用

                //方法执行后
                long endTime = System.currentTimeMillis();
                SimpleDateFormat sdf = new SimpleDateFormat();
                System.out.printf(String.format("%s方法执行结束时间:%%s ;方法执行耗时:%%d%%n"
                        , method.getName()), sdf.format(endTime), endTime - startTime);
                return result;
            }
        });
        return proxyInstance;
    }
}

CGLib动态代理

🔺基于类的动态代理
🔺提供者:第三方 CGLib
🔺使用CGLib的Enhancer类创建代理对象
🔺注意:如果报 asmxxxx 异常,需要导入 asm.jar包

public class LogCGLibProxy {
    /**
     * 生成对象的代理对象,对被代理对象进行所有方法日志增强
     * 参数:原始对象
     * 返回值:被代理的对象
     * 使用CGLib创建动态代理对象
     * 第三方提供的的创建代理对象的方式CGLib
     * 被代理对象不能用final修饰
     * 使用的是Enhancer类创建代理对象
     */
    public static Object getObjectByCGLib(final Object obj){
        /**
         * 使用CGLib的Enhancer创建代理对象
         * 参数一:对象的字节码文件
         * 参数二:方法的拦截器
         */
        Object proxyObj = Enhancer.create(obj.getClass(), new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //方法执行前
                long startTime = System.currentTimeMillis();

                Object invokeObject = method.invoke(obj, objects);//执行方法的调用

                //方法执行后
                long endTime = System.currentTimeMillis();
                SimpleDateFormat sdf = new SimpleDateFormat();
                System.out.printf(String.format("%s方法执行结束时间:%%s ;方法执行耗时:%%d%%n"
                        , method.getName()), sdf.format(endTime), endTime - startTime);
                return invokeObject;
            }
        });
        return proxyObj;
    }
}

CGLib 底层原理

    通过查看 Enhancer 类源码,最终也是生成动态代理类的字节码,动态代理类继承要被代理的类,然后实现其方法。

    和 JDK Proxy 的实现代码比较类似,都是通过实现代理器的接口,再调用某一个方法完成动态代理的,唯一不同的是,CGLib 在初始化被代理类时,是通过 Enhancer 对象把代理对象设置为被代理类的子类来实现动态代理的。

CGLib 实现步骤

创建一个实现接口 MethodInterceptor 的代理类,重写 intercept 方法;
创建获取被代理类的方法 getInstance(Object target);
获取代理类,通过代理调用方法。

两者区别

JDK Proxy 和 CGLib 的区别主要体现在以下方面:

  1. JDK Proxy 是 Java 语言自带的功能,无需通过加载第三方类实现;
  2. Java 对 JDK Proxy 提供了稳定的支持,并且会持续的升级和更新,Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多;
  3. JDK Proxy是通过拦截器加反射的方式实现的; JDK Proxy 只能代理实现接口的类; JDK Proxy 实现和调用起来比较简单;
  4. CGLib 是第三方提供的工具,基于 ASM 实现的,性能比较高;
  5. CGLib 无需通过接口来实现,它是针对类实现代理,主要是对指定的类生成一个子类,它是通过实现子类的方式来完成调用的。

Spring AOP原理–动态代理

1.AOP 思想
基于动态代理思想,对原来目标对象创建代理对象,在不修改原对象代码情况下,通过代理对象调用增强功能的代码,从而对原有业务方法进行增强。

2.AOP 作用
在不修改源代码的情况下,可以增加额外的功能,实现在原有功能基础上的增强。

3.AOP 实现原理
Spring AOP 的有两种实现方式:JDK proxy 和 CGLib 动态代理

当 Bean 实现接口时,Spring 使用 JDK proxy实现。
当 Bean 没有实现接口时,Spring 使用 CGlib 代理实现。

通过配置可以强制使用 CGlib 代理(在 spring 配置中加入 aop:aspectj-autoproxy proxy-target-class=“true”)。

4.AOP 使用场景

  • 记录日志(调用方法后记录日志)
  • 监控性能(统计方法运行时间)
  • 权限控制(调用方法前校验是否有权限)
  • 事务管理(调用方法前开启事务,调用方法后提交关闭事务 )
  • 缓存优化(第一次调用查询数据库,将查询结果放入内存对象,第二次调用,直接从内存对象返回,不需要查询数据库 )

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity脚本练习

在C# 中 class 是创建类的标志,要创建类的话得现有class上面这个的逻辑是 类的访问权限, 关键字,类名以及类继承的父类在Unity中创建一个脚本或者添加一个组件,就相当于在Unity命名空间中创建了一个可以访问的类。这些类能够直接在…

2023秋招前端面试必会的面试题

浏览器存储 我们经常需要对业务中的一些数据进行存储,通常可以分为 短暂性存储 和 持久性储存。 短暂性的时候,我们只需要将数据存在内存中,只在运行时可用持久性存储,可以分为 浏览器端 与 服务器端 浏览器: cookie: 通常用于存储…

springboot健身房管理系统

springboot健身房管理系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍&#xf…

Vue 3.0 单文件组件 【Vue3 从零开始】

#介绍 在很多 Vue 项目中,我们使用 app.component 来定义全局组件,紧接着用 app.mount(#app) 在每个页面内指定一个容器元素。 这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。但当在更复杂的…

HTTP 3.0来了,UDP取代TCP成为基础协议,TCP究竟输在哪里?

TCP 是 Internet 上使用和部署最广泛的协议之一,多年来一直被视为网络基石,随着HTTP/3正式被标准化,QUIC协议成功“上位”,UDP“取代”TCP成为基础协议,TCP究竟“输”在哪里? HTTP/3 采用了谷歌多年探索的基…

< CSS小技巧:那些不常用,却很惊艳的CSS属性 >

文章目录👉 前言👉 一. background-clip: text - 限制背景显示(裁剪)👉 二. user-select - 控制用户能否选中文本👉 三. :focus-within 伪类👉 四. gap - 网格 / 弹性布局间隔设置👉…

【C++笔试强训】第三十一天

🎇C笔试强训 博客主页:一起去看日落吗分享博主的C刷题日常,大家一起学习博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话:夜色难免微凉,前方必有曙光 🌞。 选择题 &#x…

Golang每日一练(leetDay0005)

目录 13. 罗马数字转整数 Roman to Integer ★ 14. 最长公共前缀 Longest Common Prefix ★ 15. 三数之和 3Sum ★★★ 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 13. 罗马数字转…

我从功能测试到python接口自动化测试涨到22k,谁知道我经历了什么......

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 常见的接口&#xf…

C++高并发内存池的设计和实现

一、整体设计 1、需求分析 池化技术是计算机中的一种设计模式,内存池是常见的池化技术之一,它能够有效的提高内存的申请和释放效率以及内存碎片等问题,但是传统的内存池也存在一定的缺陷,高并发内存池相对于普通的内存池它有自己…

卷王都在偷偷准备金三银四了...

年终奖没发; 简历石沉大海; 发消息只读不回 打开某招聘,看了看岗位,这个厂还不错,可是要求好高,我啥都不会。 “哎,算了,我简历还没更新呢,我躺到6月份拿到年终奖再跑…

3-1 SpringCloud快速开发入门: Ribbon 是什么

接上一章节Eureka 服务注册中心自我保护机制,这里讲讲Ribbon 是什么 Ribbon 是什么 通常说的负载均衡是指将一个请求均匀地分摊到不同的节点单元上执行,负载均和分为硬件负载均衡和软件负载均衡: **硬件负载均衡:**比如 F5、深信…

记第一次面试的过程(C++)

说实话三月份上旬过得很充实,而且感觉蛮值,但还有不足的地方,今晚特地看完资料分析来复盘复盘。 时间还要回到3.2中午13.35(别问我为什么那么准确,刚刚掏手机看的),我正在吃着饭看着王者荣耀的直…

STL sort 分析

前言 STL 中提供了很多算法,sort 是我们经常使用的,那它究竟是如何实现的呢? STL 的 sort 算法,数据量大时采用快速排序,分段递归。一旦分段的数据量小于某个门槛,为避免快速排序的递归调用带来过大的额外…

三天吃透计算机网络面试八股文

本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~ Github地址:https://github.com/…

Linux常用命令

个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。座右铭:海不辞水,故能成其大;山不辞石,故能成其高。个人主页:小李会科技的…

C++STL 容器案例 员工分组 实现步骤与代码分析与展示 实现步骤的注意事项

STL容器 员工分组案例 文章目录STL容器 员工分组案例1 案例描述2 实现步骤3 案例代码与分析1 案例描述 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在哪个部门工作员工信息有: 姓名 工资组成&#xf…

CANoe中使用CAPL刷写流程详解(Trace图解)(CAN总线)

🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】🍅 玩转CANoe&…

史上最全最详细的Java架构师成长路径图,程序员必备

从新手码农到高级架构师,要经过几步?要多努力,才能成为为人倚重的技术专家?本文将为你带来一张程序员发展路径图,但你需要知道的是,天下没有普适的道理,具体问题还需具体分析,实践才…

Verilog实现组合逻辑电路

在verilog 中可以实现的数字电路主要分为两类----组合逻辑电路和时序逻辑电路。组合逻辑电路比较简单,仅由基本逻辑门组成---如与门、或门和非门等。当电路的输入发生变化时,输出几乎(信号在电路中传递时会有一小段延迟)立即就发生…
最新文章