【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?

这篇具有很好参考价值的文章主要介绍了【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?

目录

一、Java动态代理的实现

1、使用JDK Proxy实现动态代理

2、使用CGLib实现动态代理

二、JDK Proxy 与 CGLib 的区别

三、Spring中的动态代理

四、 Lombok代理原理

总结


前言

本文深入探讨了Java动态代理的实现机制,分别介绍了使用JDK Proxy和CGLib两种不同方式来实现动态代理。

文章进一步对比了JDK Proxy与CGLib的主要区别,JDK Proxy主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,它允许在运行时动态创建实现了一组接口的代理类实例,但仅限于代理那些已实现接口的类。相比之下,CGLib通过在运行时生成目标类的子类来实现代理,从而克服了JDK Proxy只能代理接口的限制。包括代理对象的类型、性能差异、使用场景以及依赖问题。尽管两者都可以实现动态代理,但选择哪一种方式取决于具体需求:如果目标对象已经实现了接口,则JDK Proxy是一个简单直接的选择;若需要代理没有实现接口的普通类,则CGLib是更合适的选择。

文中还探讨了Spring框架中动态代理的应用,Spring可以根据情况自动选择使用JDK Proxy或CGLib来实现代理,为开发者提供了更高层次的抽象和便利。同时,也简要介绍了Lombok库是如何利用代理原理来减少样板代码并提高开发效率的。

一、Java动态代理的实现

Java动态代理主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现。其基本思想是,在运行时动态创建一个实现了一组接口的代理类的实例,然后将对该实例的所有方法调用转发给一个处理器(即实现了InvocationHandler接口的类的实例)。

Java动态代理是Java高级编程中的一项强大功能,它允许开发者在运行时创建代理实例来控制对其他对象的访问。这种技术广泛应用于AOP(面向切面编程)、RPC(远程过程调用)框架、事务管理等领域。本文旨在深入探讨Java动态代理的实现机制,并比较JDK Proxy和CGLib两种实现方式的异同。

动态代理的常用实现方式是反射。反射机制是指程序在运行期间可以访问、检测和修改其本身状态或行为的一种能力,使用反射我们可以调用任意一个类对象,以及类对象中包含的属性及方法。

动态代理可以通过 CGLib 来实现,而 CGLib 是基于 ASM(一个 Java 字节码操作框架)而非反射实现的。

简单来说,动态代理是一种行为方式,而反射或 ASM 只是它的一种实现手段而已。

1、使用JDK Proxy实现动态代理

JDK动态代理只能代理实现了接口的类。

  • 定义接口:首先定义一个或多个接口,以及它们的实现类。
  • 创建InvocationHandler:实现InvocationHandler接口,重写invoke方法。在这里可以插入自定义的逻辑,比如日志记录、权限检查等。
  • 生成代理对象:通过调用Proxy.newProxyInstance方法,传入类加载器、接口数组以及InvocationHandler实例,来动态生成代理对象。
public interface Subject {
    void doSomething();
}

public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Before advice
        System.out.println("Before method call");
        Object result = method.invoke(target, args);
        // After advice
        System.out.println("After method call");
        return result;
    }
}

Subject subject = (Subject) Proxy.newProxyInstance(
    RealSubject.class.getClassLoader(),
    new Class[]{Subject.class},
    new MyInvocationHandler(new RealSubject())
);

subject.doSomething();

2、使用CGLib实现动态代理

与JDK Proxy不同,CGLib能够代理未实现接口的类。它通过在运行时动态生成被代理类的子类,来拦截对父类方法的调用。

  • 定义类:直接定义一个类,而非接口及其实现。
  • 创建MethodInterceptor:实现MethodInterceptor接口,重写intercept方法,在该方法中添加自定义逻辑。
  • 生成代理对象:通过使用CGLib提供的Enhancer类,设置父类和回调,从而创建代理对象。
public class RealSubject {
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // Before advice
        System.out.println("Before method call");
        Object result = proxy.invokeSuper(obj, args);
        // After advice
        System.out.println("After method call");
        return result;
    }
});


RealSubject subject = (RealSubject) enhancer.create();
subject.doSomething();

二、JDK Proxy 与 CGLib 的区别

尽管JDK Proxy和CGLib都可用于实现Java动态代理,但它们之间存在一些关键差异:

  1. 代理对象类型:JDK Proxy只能代理实现了接口的类;而CGLib可以直接代理普通类。
  2. 性能:CGLib在运行时生成代理类的子类,通常认为其性能略优于JDK Proxy。但在大多数场景下,这种性能差异不大。
  3. 使用场景:如果目标对象已经实现了接口,使用JDK Proxy是一个简单直接的选择。如果需要代理没有实现接口的类,则必须使用CGLib。
  4. 依赖:JDK Proxy无需额外依赖,因为它是Java核心库的一部分;而CGLib需要添加CGLib库作为项目依赖。
  5. JDK Proxy 是 Java 语言自带的功能,无需通过加载第三方类实现;
  6. Java 对 JDK Proxy 提供了稳定的支持,并且会持续的升级和更新 JDK Proxy,例如 Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多;
  7. JDK Proxy 是通过拦截器加反射的方式实现的;
  8. JDK Proxy 只能代理继承接口的类;
  9. JDK Proxy 实现和调用起来比较简单;
  10. CGLib 是第三方提供的工具,基于 ASM 实现的,性能比较高;
  11. CGLib 无需通过接口来实现,它是通过实现子类的方式来完成调用的。

三、Spring中的动态代理

动态代理的常见使用场景有 RPC 框架的封装、AOP(面向切面编程)的实现、JDBC 的连接等。

Spring 框架中同时使用了两种动态代理 JDK Proxy 和 CGLib,当 Bean 实现了接口时,Spring 就会使用 JDK Proxy,在没有实现接口时就会使用 CGLib,我们也可以在配置中指定强制使用 CGLib,只需要在 Spring 配置中添加  <aop:aspectj-autoproxy proxy-target-class="true"/>  即可。

四、 Lombok代理原理

Lombok是一个工具类可以解决又重复的代码,如 Setter、Getter、toString、equals 和 hashCode 等等,向这种方法都可以使用 Lombok 注解来完成。 需要在 IDE 中安装 Lombok 插件,如下图所示:

【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?,Java全栈白宝书,# Java核心技术,java,开发语言,服务器,spring,后端,jvm,ide

Lombok 的实现和反射没有任何关系,Lombok 是在编译期就为我们生成了对应的字节码其实 Lombok 是基于 Java 1.6 实现的 JSR 269: Pluggable Annotation Processing API 来实现的,也就是通过编译期自定义注解处理器来实现的,它的执行步骤如下:

【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?,Java全栈白宝书,# Java核心技术,java,开发语言,服务器,spring,后端,jvm,ide

 从流程图中可以看出,在编译期阶段,当 Java 源码被抽象成语法树(AST)之后,Lombok 会根据自己的注解处理器动态修改 AST,增加新的代码(节点),在这一切执行之后就生成了最终的字节码(.class)文件,这就是 Lombok 的执行原理。

总结

Java动态代理是Java高级编程中的一个强大工具,它提供了一种灵活的方式来增强方法调用。通过对比JDK Proxy和CGLib,可以看出每种方法各有优势和适用场景。选择合适的动态代理实现方式,可以帮助开发者编写更加灵活和高效的代码。在实际开发中,根据具体需求选择最适合的代理方式,是提升项目质量和维护性的关键。

如果本文对你有帮助 欢迎 关注 、点赞 、收藏 、评论, 博主才有动力持续记录遇到的问题!!!

博主v:XiaoMing_Java

 📫作者简介:嗨,大家好,我是  小明(小明Java问道之路)互联网大厂后端研发专家,2022博客之星TOP3 / 博客专家 / CSDN后端内容合伙人、InfoQ(极客时间)签约作者、阿里云签约博主、全网 6 万粉丝博主。


🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

专栏系列(点击解锁)

学习路线(点击解锁)

知识定位

🔥Redis从入门到精通与实战🔥

Redis从入门到精通与实战

围绕原理源码讲解Redis面试知识点与实战

🔥MySQL从入门到精通🔥

MySQL从入门到精通

全面讲解MySQL知识与企业级MySQL实战

🔥计算机底层原理🔥

深入理解计算机系统CSAPP

以深入理解计算机系统为基石,构件计算机体系和计算机思维

Linux内核源码解析

围绕Linux内核讲解计算机底层原理与并发

🔥数据结构与企业题库精讲🔥

数据结构与企业题库精讲

结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

🔥互联网架构分析与实战🔥

企业系统架构分析实践与落地

行业最前沿视角,专注于技术架构升级路线、架构实践

互联网企业防资损实践

互联网金融公司的防资损方法论、代码与实践

🔥Java全栈白宝书🔥

精通Java8与函数式编程

本专栏以实战为基础,逐步深入Java8以及未来的编程模式

深入理解JVM

详细介绍内存区域、字节码、方法底层,类加载和GC等知识

深入理解高并发编程

深入Liunx内核、汇编、C++全方位理解并发编程

Spring源码分析

Spring核心七IOC/AOP等源码分析

MyBatis源码分析

MyBatis核心源码分析

Java核心技术

只讲Java核心技术文章来源地址https://www.toymoban.com/news/detail-839667.html

到了这里,关于【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java——JDK动态代理

    动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益的最大化,此时就可以请律师帮助自己不仅完成对案件的陈述

    2024年02月09日
    浏览(38)
  • Java代理之jdk动态代理+应用场景实战

    本文将先介绍jdk动态代理的基本用法,并对其原理和注意事项予以说明。之后将以两个最常见的应用场景为例,进行代码实操。这两个应用场景分别是 拦截器 和 声明性接口 ,它们在许多开发框架中广泛使用。比如在spring和mybatis中均使用了拦截器模式,在mybatis中还利用动态

    2023年04月10日
    浏览(42)
  • Java中的代理模式(二)JDK动态代理

    大家好👋,我是极客涛😎,上一篇中我们对代理模式有两大类,静态代理和动态代理,对于静态代理相信大家都信手拈来。对于动态代理还有两种实现,一种是java原生的Jdk代理,一种是Cglib方式。因为涉及到源码解读,所以我也将分两期完成,本期主要讲讲JDK动态代理的实

    2024年01月22日
    浏览(38)
  • java的动态代理如何实现

    jdkproxy动态代理必须基于接口(interface)实现 接口 UserInterface.java 原始实现类: UseServiceImpl.java 代理类 : UserProxyFactoryBJdk.java 执行结果: before the name of 123is Austin after Cglib实现动态代理与JdkProxy不同, 是通过构建继承类实现 原始类 UseServiceImpl.java 代理类 : UserProxyFactoryByCglib.ja

    2024年02月09日
    浏览(42)
  • [Java]静态代理、动态代理(基于JDK1.8)

    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18002823 出自【进步*于辰的博客】 参考笔记一,P83;笔记二,P75.4。 目录 1、概述 2、静态代理的两种形式 2.1 面向接口 2.2 面向继承 3、动态代理的两种形式 3.1 JDK动态代理

    2024年03月09日
    浏览(36)
  • 【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件)

       📝个人主页:哈__ 期待您的关注  想要学代理模式,我们就要先弄清一个概念 “什么是代理”? 在我们的现实生活中,你或许不少听过关于代理的名词,如:代理商。那什么又叫做代理商?让我一个词来形容就是 中间商。 举个例子,在你买二手房的时候,你一般不会直

    2024年04月15日
    浏览(43)
  • java基础之Java的动态代理如何实现

    目录 Java实现动态代理的两种方式 两种动态代理的区别 JDK 的动态代理是基于接口的代理。 CGLIB 是基于继承的代理。 总结 补充 静态代理和动态代理的区别 动态代理的用途 Spring AOP的实现方式 JDK 动态代理代码示例 Cglib动态代理代码示例 JDK动态代理 :Java.lang.reflect 包中的Pr

    2024年02月03日
    浏览(36)
  • golang 如何实现proxy代理

    匿名浏览:代理服务器可以隐藏用户的真实IP地址,使用户在访问网站时保持匿名性,保护隐私。 访问控制:代理服务器可以用于限制用户对特定网站或内容的访问。例如,企业可以使用代理服务器来限制员工对某些社交媒体网站的访问。 内容过滤:代理服务器可以根据预设

    2024年02月14日
    浏览(32)
  • 代理模式 静态代理和动态代理(jdk、cglib)——Java入职第十一天

            一个类代表另一个类去完成扩展功能,在主体类的基础上,新增一个代理类,扩展主体类功能,不影响主体,完成额外功能。比如买车票,可以去代理点买,不用去火车站,主要包括静态代理和动态代理两种模式。 代理类中包含了主体类 无法根据业务扩展,每一次

    2024年02月10日
    浏览(48)
  • Spring之CGLIB和JDK动态代理底层实现

    目录 CGLIB 使用示例-支持创建代理对象,执行代理逻辑 使用示例-多个方法,走不同的代理逻辑 JDK动态代理 使用示例-支持创建代理对象,执行代理逻辑 ProxyFactory 如何自动在CGLIB和JDK动态代理转换 使用示例-使用CGLIB代理方式 使用示例-使用JDK动态代理方式 Spring会自动在JDK动态

    2024年04月25日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包