前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解JDK动态代理

深入理解JDK动态代理

作者头像
windealli
发布于 2024-06-25 12:35:42
发布于 2024-06-25 12:35:42
31600
代码可运行
举报
文章被收录于专栏:windealliwindealli
运行总次数:0
代码可运行

一、什么是JDK动态代理

1. 什么是代理模式(Proxy Pattern)

代理模式是一种设计模式,它通过为其他对象提供一个代理或占位符来控制对原始对象的访问。即通过代理对象访问目标对象。

代理模式可以在不修改原始类代码的情况下,通过代理类,添加一些功能操作,比如添加方法调用的预处理、后处理等。

代理模式的基本概念包括以下几个部分:

  • 抽象对象(Subject): 这是一个接口,定义了代理对象和具体对象的公共接口,这样在任何使用具体对象的地方都可以使用代理对象。
  • 具体对象(RealSubject): 被代理的对象。 代理对象(Proxy): 包含了对具体对象的引用,从而可以在任何时候操作具体对象;代理对象提供了一个与具体对象相同的接口,所以它可以被当作具体对象使用。代理对象通常在客户端调用传递给实际对象之前或之后,执行某个操作,而不是只处理调用并将调用传递给实际对象。

Java中,代理模式的实现通常可以通过接口实现,但是也可以通过类或者抽象类实现。

2. 静态代理与动态代理

  • 静态代理 静态代理在编译时就已经实现,代码在编译时就已经确定,并已经被转换为字节码文件。
  • 动态代理 动态代理是在运行时动态生成的,即编译完成后还没有实际的代理对象,只有在运行时才会创建。

3. JDK动态代理

JDK动态代理是Java原生支持的代理方式,它允许开发者在运行时动态地创建和使用代理对象。这种方式主要依赖于Java的反射技术。

二、JDK动态代理的基本原理

1. JDK动态代理的工作原理

JDK动态代理的工作原理是在运行时在内存中动态地创建一个接口的实现类。

当我们通过代理类的对象调用方法时,它实际上会调用定义的InvocationHandler接口的实现类对象的invoke方法。然后在invoke方法中我们可以定义预处理、调用目标方法、后处理等,我们也可以选择不调用目标对象的方法。这样,我们就可以在不修改源码的情况下,实现对目标对象的功能增强。

2. JDK动态代理的关键组件:InvocationHandlerProxy

JDK动态代理主要涉及到java.lang.reflect包中的两个类:ProxyInvocationHandler。Proxy类是所有动态代理类的父类,它有一个名为newProxyInstance的方法,这个方法生成动态代理对象。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。

  • InvocationHandler:它是一个接口,我们必须实现该接口。我们可以通过实现该接口的invoke方法,定义横切逻辑,然后通过反射机制调用目标类的代码。动态的将横切逻辑和业务逻辑编织在一起。
  • ProxyProxy类是所有动态代理类的父类,它有一个名为newProxyInstance的方法,这个方法生成动态代理对象;newProxyInstance方法接收三个参数: 并返回一个新的代理对象(对象实现了指定的接口)。
    • ClassLoader loader(类加载器)、
    • Class<?>[] interfaces(给代理对象提供的接口)、
    • InvocationHandler h(调用处理器),

三、JDK动态代理的实现步骤

1. 定义一个接口和它的实现类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface MyInterface {
    void doSomething();
}

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

2. 创建InvocationHandler对象,自定义invoke 方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 {
        System.out.println("Before method...");
        Object result = method.invoke(target, args);
        System.out.println("After method...");
        return result;
    }
}

3. 使用Proxy 类生成代理对象,并调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {
    public static void main(String[] args) {
        MyInterface myInterface = new MyInterfaceImpl();
        InvocationHandler handler = new MyInvocationHandler(myInterface);
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                myInterface.getClass().getClassLoader(),
                myInterface.getClass().getInterfaces(),
                handler);
        proxy.doSomething();
    }
}

运行以上代码,得到输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Before method...
Doing something...
After method...

四、JDK动态代理的实际应用

1. AOP(面向切面编程)中的应用

AOP是一种编程范式,其目标是提高程序模块化的程度。

在AOP中,切面(Aspect)是包含横切关注点实现的模块。切点(Pointcut)定义了在何处应用切面的代码逻辑。连接点(Joinpoint)是程序执行过程中的某个特定点,如方法调用或异常抛出。通知(Advice)是切面在特定连接点执行的动作。

JDK动态代理可以用于实现AOP中的通知。通过创建目标类的代理对象,我们可以在调用目标方法之前、之后或在抛出异常时插入自定义的逻辑。以下是一个简单的示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class LoggingAspect implements InvocationHandler {
    private Object target;

    public LoggingAspect(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

// 使用JDK动态代理创建代理对象
MyService myService = (MyService) Proxy.newProxyInstance(
        MyService.class.getClassLoader(),
        new Class<?>[]{MyService.class},
        new LoggingAspect(new MyServiceImpl()));

// 调用代理对象的方法
myService.doSomething();

2. Spring框架中的应用

动态代理在Spring框架中有广泛的应用,

  • Spring的AOP功能 就是基于动态代理实现的,当我们在Spring中配置一个bean为代理对象时,Spring会自动为这个bean创建一个代理对象。当我们调用bean的方法时,实际上是调用了代理对象的方法。这样,我们就可以在代理对象的方法中添加一些额外的逻辑,例如事务管理、日志记录等。
  • Spring的事务管理 也是通过动态代理实现的。当我们在方法上添加@Transactional注解时,Spring会为这个方法创建一个代理对象,用于在方法执行前后添加事务管理的代码。

在Spring中使用JDK动态代理时,我们需要定义一个切面(Aspect),并在切面中指定切点和通知。以下是一个简单的示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Aspect
public class LoggingAspect {
    @Before("execution(* com.example.MyService.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.MyService.*(..))")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }
}

// 在Spring配置类中启用AOP自动代理
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}

在这个示例中,我们使用了@Aspect注解来标记LoggingAspect类作为一个切面。@Before@After注解分别定义了前置通知和后置通知。execution表达式指定了切点,表示这些通知将应用于com.example.MyService类的所有方法。通过在Spring配置类中启用AOP自动代理,我们可以确保Spring会为匹配切点的方法创建代理对象,并应用相应的通知。

五、JDK动态代理的优缺点

1. 优点

  • 实现简单: JDK动态代理使用Java反射机制生成代理对象,不需要我们手动创建代理类。
  • 无嵌入性: 只需要实现InvocationHandler接口和创建代理类即可。对于简单的需求,这种方法是快速且易于实现的。
  • 动态性: JDK动态代理能够在运行时根据需要动态地创建代理对象,这为程序的扩展性和灵活性提供了支持。
  • **解耦:**通过代理模式,可以将目标对象与横切逻辑分离,降低了代码之间的耦合度,提高了代码的可维护性。
  • 跨平台: JDK动态代理是基于Java反射机制实现的,因此具有跨平台的特性。

2. 缺点

  • 性能开销: JDK动态代理使用反射机制来调用目标方法,这会导致一定程度的性能损失。尽管JVM对反射进行了优化,但在某些性能敏感的场景下,可能仍然不是最佳选择。
  • 仅支持接口代理: JDK动态代理只能为接口创建代理类,无法直接为类创建代理。这意味着如果目标对象没有实现任何接口,JDK动态代理将无法使用。
  • 代理类数量: 对于每个需要代理的接口,JDK动态代理都会生成一个新的代理类。如果有大量接口需要代理,这可能导致代理类数量过多,增加了部署和管理的复杂性。
  • 横切逻辑限制: JDK动态代理的横切逻辑必须实现为InvocationHandler接口的方法,这限制了横切逻辑的灵活性和多样性,无法处理复杂的情况。

六、CGLIB动态代理(拓展)

1. CGLIB动态代理的基本原理:

CGLIB(Code Generation Library)是一个开源项目,它提供了在运行时动态生成Java类的能力。CGLIB动态代理的基本原理是通过继承的方式进行代理。当我们对一个类进行CGLIB动态代理时,CGLIB会动态生成一个子类来继承这个类,然后在子类中添加我们的代理逻辑。当我们调用目标方法时,实际上是调用了子类的方法。因此,CGLIB动态代理可以代理任何类,不仅仅是接口。

2. JDK动态代理与CGLIB动态代理的比较:

  • JDK动态代理只能代理实现了接口的类,而CGLIB动态代理可以代理任何类。
  • JDK动态代理是通过反射机制实现的,而CGLIB动态代理是通过生成一个被代理类的子类来实现的。
  • 由于CGLIB动态代理生成的是子类,所以在性能上可能会比JDK动态代理稍微好一些,但是生成的类较多,可能会占用更多的内存。
  • 在Spring框架中,如果一个类没有实现接口,那么Spring会默认使用CGLIB进行动态代理。如果一个类实现了接口,Spring会优先使用JDK动态代理。如果要强制使用CGLIB,可以在Spring配置中进行设置。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海天二路搬砖工 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
太好了!总算有人把动态代理、CGlib、AOP都说清楚了!
静态代理是代理类在编译期间就创建好了,不是编译器生成的代理类,而是手动创建的类。在编译时就已经将接口,被代理类,代理类等确定下来。,软件设计中所指的代理一般是指静态代理,也就是在代码中显式指定的代理。
Bug开发工程师
2019/07/12
45.2K3
深入理解Java的JDK动态代理
代理模式是一种设计模式,它通过为其他对象提供一个代理或占位符来控制对原始对象的访问。即通过代理对象访问目标对象。
windealli
2024/06/19
6300
深入理解Java的JDK动态代理
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
在现代Java应用程序开发中,Spring Boot是一个备受欢迎的框架,它为开发人员提供了强大的工具来创建可扩展、易维护的应用程序。其中一个关键功能是AOP(面向切面编程),它允许我们在不侵入应用程序核心逻辑的情况下添加各种功能。在这篇博客中,我们将深入探讨Spring Boot中AOP的两个主要代理方式:CGLIB和JDK动态代理。我们将揭开它们的工作原理、适用场景以及如何使用它们来实现强大的切面功能。
一只牛博
2025/05/30
1010
AOP中的JDK动态代理与CGLIB动态代理:深度解析与实战
这里推荐一篇实用的文章:《Java 读取寄存器数据的实现与应用》,作者:【喵手】。
小马哥学JAVA
2024/11/21
2320
探索Java动态代理的奥秘:JDK vs CGLIB
动态代理是一种在 运行时动态生成代理类 的技术,无需手动编写代理类代码。它通过拦截目标方法的调用,实现对核心逻辑的 无侵入式增强(如日志、事务、权限控制等)。
用户7954602
2025/02/04
1550
探索Java动态代理的奥秘:JDK vs CGLIB
Java-JDK动态代理
Java1.3以后,JAVA提供了动态代理技术,允许开发者在运行期创建接口的代理实例。
小小工匠
2021/08/16
2560
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
   ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的接口),当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;
红目香薰
2022/11/29
3170
Spring系列七:JDK 动态代理和 CGLIB 代理
Spring的AOP是通过动态代理来实现的,动态代理主要有两种方式JDK动态代理和Cglib动态代理,这两种动态代理的使用和原理有些不同。
叶秋学长
2022/07/27
4340
Spring系列七:JDK 动态代理和 CGLIB 代理
Java-JDK动态代理(AOP)
使用JDK的反射机制,创建对象的能力,创建的时代理类的对象.而不用我们创建类的文件.
Java架构师必看
2021/05/14
2820
Java-JDK动态代理(AOP)
SpringJDK动态代理
前面文章我们学习了关于Spring的IOC与AOP相关知识点,在此之前,我们主要学习Spring的一些核心概念,IOC和AOP等等。我们之前学习了简单了解了AOP如何借助动态字节码技术来构建动态代理类。实现动态代理的方式不止一种。本次系列文章主要介绍两种:JDK动态代理和CGlib动态代理,主要主要介绍JDK动态代理。首先,我们将着重了解JDK动态代理的核心原理和实际应用情境。好了,话不多说,让我们开始吧😎😎😎。
程序员Leo
2023/11/16
2140
SpringJDK动态代理
JDK动态代理、Cglib动态代理及Spring AOP
Java中的JDK动态代理是一种通过反射机制生成代理对象的技术,使得我们能够在运行时动态地创建某个接口的代理类,而无需手动编写实现类。JDK动态代理通常用于横切关注点(如日志、事务管理、安全性等)在方法调用前后进行处理,而不需要修改目标类的源代码。
意疏
2024/12/31
2420
JDK动态代理、Cglib动态代理及Spring AOP
Spring AOP中的JDK和CGLib动态代理哪个效率更高?
今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高?
全栈程序员站长
2022/08/14
3190
Spring AOP中的JDK和CGLib动态代理哪个效率更高?
【面试题精讲】JDK动态代理
JDK 动态代理是 Java 中一种实现代理模式的机制。它允许在运行时创建代理类和对象,用于替代原始对象进行方法调用,并可以在方法调用前后添加额外的逻辑。
程序员朱永胜
2023/10/10
5260
面试造火箭系列,栽在了cglib和jdk动态代理
“喂,你好,我是XX巴巴公司的技术面试官,请问你是张小帅吗”。声音是从电话那头传来的
程序员老猫
2022/01/04
2560
Spring学习笔记之aop动态代理(3)
1.0 静态代理模式的缺点: 1、在该系统中有多少的dao就的写多少的proxy,麻烦 2、如果目标接口有方法的改动,则proxy也需要改动。 PersonDao.java
王小雷
2019/05/26
2550
【面试系列】JDK动态代理和CGLIB静态代理 - Java技术债务
是否在面试过程中经常被问到Spring的代理的问题:比如说几种代理方式?两种代理方式的区别?或者问为什么JDK动态代理只能代理接口?
Java技术债务
2024/06/21
1230
【面试系列】JDK动态代理和CGLIB静态代理 - Java技术债务
jdk静态代理,jdk动态代理,cglib动态代理
代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道。如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法。如果公司卖多少钱,代理商也卖多少钱,那么代理商就赚不了钱。所以代理商在调用公司的卖方法后,加上自己的利润然后再把产品卖给客户。而客户部直接跟公司打交道,或者客户根本不知道公司的存在,然而客户最终却买到了产品。
互扯程序
2019/07/01
5180
jdk静态代理,jdk动态代理,cglib动态代理
从根上理解Cglib与JDK动态代理
最近在阅读到了Spring源码对于两种动态代理使用在不同场景下的使用,两种方式各有利弊写一篇文加深自己的认识。文中对于源码的涉及较少,更多的是作者自己的理解和举例,然后通过部分源码验证。
科技新语
2023/03/07
4410
动态代理机制
代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。 换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。 客户类真正想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。代理类与目标类要实现同一个接口。 例如:有A,B,C三个类,A原来可以调用C类的方法,现在因为某种原因C类不允许A类调用其方法,但B类可以调用C类的方法,A类通过B类调用C类的方法。这里B是C的代理,A通过代理B访问C。 原来的访问关系:
技术交流
2022/11/18
2490
动态代理机制
深入理解JDK动态代理
代理模式的目的是在不修改原有类方法设计的基础上,对方法行为进行增强。
大猫的Java笔记
2021/05/13
3280
相关推荐
太好了!总算有人把动态代理、CGlib、AOP都说清楚了!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验