滚雪球学Java(25):动态代理

简介: 【4月更文挑战第14天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!!


前言

在Java开发中,经常会使用代理模式来实现一些特殊的需求,例如AOP编程、RPC调用等。Java中的代理模式主要有静态代理和动态代理两种,其中静态代理需要手动编写一个代理类,而动态代理则可以在运行时动态生成代理类,更加灵活方便。

本文将介绍Java中的动态代理,包括动态代理的实现原理、使用方法、以及动态代理实现中的常见问题和注意事项。

摘要

本文将分以下几部分介绍Java中的动态代理:

  1. 动态代理的概念和实现原理。
  2. Java中的动态代理实现。
  3. 动态代理的常见问题和注意事项。

内容

1. 动态代理的概念和实现原理

代理模式是一种常用的设计模式,它可以在不改变原有代码的前提下,实现对原有代码的扩展。代理模式主要有静态代理和动态代理两种。

在Java中,静态代理需要手动编写一个代理类,其中代理类需要实现与被代理对象相同的接口方法,并在方法中调用被代理对象的对应方法。而动态代理则是在运行时动态生成代理类,更加灵活方便。

Java中的动态代理主要使用了Java反射机制,通过反射动态生成代理类并调用其中的方法。动态代理需要实现一个代理接口,在运行时使用反射动态生成一个代理类,该代理类实现了代理接口,并在其中调用了InvocationHandler中的invoke()方法。

在Java中,动态代理主要由两个类来实现:java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。其中,Proxy类用于生成动态代理类对象,而InvocationHandler接口则用于实现具体的代理逻辑。在使用动态代理时,需要创建一个InvocationHandler对象,并将其作为参数传递给Proxy.newProxyInstance()方法,该方法将返回一个代理对象。

2. Java中的动态代理实现

Java中的动态代理主要使用了java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler两个类。在使用动态代理时,需要创建一个InvocationHandler对象,并将其作为参数传递给Proxy.newProxyInstance()方法,该方法将返回一个代理对象。

下面是一个简单的示例,展示了如何使用动态代理:

interface Subject {
   
    void request();
}

class RealSubject implements Subject {
   
    public void request() {
   
        System.out.println("RealSubject request()");
    }
}

class DynamicProxy implements InvocationHandler {
   
    private Object subject;

    public DynamicProxy(Object subject) {
   
        this.subject = subject;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
        System.out.println("before");
        Object result = method.invoke(subject, args);
        System.out.println("after");
        return result;
    }
}

public class Test {
   
    public static void main(String[] args) {
   
        RealSubject realSubject = new RealSubject();
        InvocationHandler handler = new DynamicProxy(realSubject);
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);
        subject.request();
    }
}

在这个例子中,我们定义了一个Subject接口和一个RealSubject类。DynamicProxy类是我们定义的代理类,用于实现代理逻辑。在实现代理逻辑时,我们使用了InvocationHandler接口,并在其中实现了before()和after()方法,用于在代理的方法执行前后进行处理。

在main()方法中,我们首先创建了一个RealSubject对象,然后创建了一个DynamicProxy对象,将RealSubject对象传递给它。接着,我们使用Proxy.newProxyInstance()方法创建了一个代理对象,并将该代理对象强制转换为Subject类型。最后,我们调用了代理对象的request()方法,该方法会自动调用DynamicProxy中的invoke()方法,从而实现了代理逻辑。

3. 动态代理的常见问题和注意事项

动态代理虽然使用灵活方便,但在实现时也需要注意一些问题:

  1. 基于接口的代理:在Java中,动态代理只能基于接口实现。如果需要基于实现类实现动态代理,则需要使用字节码工具类,例如ASM和CGLIB。
  2. 方法调用循环问题:在动态代理中,如果代理对象调用了被代理对象的方法,将会导致invoke()方法被重复调用,从而导致死循环。为了避免这个问题,我们可以在invoke()方法中判断是否为代理对象,以避免调用被代理对象的方法。
  3. hashCode和equals方法的问题:在动态代理中,由于代理类和被代理类是两个不同的类,因此它们的hashCode和equals方法会有不同的实现。如果需要在代理对象中使用hashCode和equals方法,需要特别处理。

测试用例

interface Calculator {
   
    int add(int a, int b);
    int subtract(int a, int b);
}

class CalculatorImpl implements Calculator {
   
    public int add(int a, int b) {
   
        return a + b;
    }
    public int subtract(int a, int b) {
   
        return a - b;
    }
}

class CalculatorProxy implements InvocationHandler {
   
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
        System.out.println("before");
        Object result = method.invoke(target, args);
        System.out.println("after");
        return result;
    }
}

public class Test {
   
    public static void main(String[] args) {
   
        Calculator calculator = new CalculatorImpl();
        InvocationHandler handler = new CalculatorProxy(calculator);
        Calculator proxy = (Calculator) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                calculator.getClass().getInterfaces(), handler);
        System.out.println("add(1, 2) = " + proxy.add(1, 2));
        System.out.println("subtract(5, 3) = " + proxy.subtract(5, 3));
    }
}

该测试用例演示了如何使用动态代理实现一个简单的计算器。其中,Calculator接口定义了add()和subtract()两个方法,CalculatorImpl类是真正的计算器实现类,而CalculatorProxy类是代理类,用于实现代理逻辑。

在测试用例中,我们首先创建了一个CalculatorImpl对象,然后创建了一个CalculatorProxy对象,将CalculatorImpl对象传递给它。接着,我们使用Proxy.newProxyInstance()方法创建了一个代理对象,并将该代理对象强制转换为Calculator类型。最后,我们调用了代理对象的add()和subtract()方法,并输出了它们的返回值。

全文小结

本文介绍了Java中的动态代理,包括动态代理的概念和实现原理、Java中的动态代理实现、以及动态代理实现中的常见问题和注意事项。动态代理可以在不改变原有代码的前提下,实现对原有代码的扩展,非常灵活方便。在使用动态代理时,需要注意基于接口的代理、方法调用循环问题以及hashCode和equals方法的问题。

附录源码

  如上涉及所有源码均已上传同步在Gitee,提供给同学们一对一参考学习,辅助你更迅速的掌握。

☀️建议/推荐你


  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学Java」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门Java编程,就像滚雪球一样,越滚越大,指数级提升。

目录
相关文章
|
2月前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
25 0
[Java]静态代理与动态代理(基于JDK1.8)
|
2月前
|
Java
深入理解Java动态代理
深入理解Java动态代理
19 1
|
2月前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
2月前
|
设计模式 缓存 Java
从源码学习Java动态代理|8月更文挑战
从源码学习Java动态代理|8月更文挑战
|
5月前
|
缓存 Java 测试技术
day27:Java零基础 - 动态代理
【7月更文挑战第27天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
43 2
day27:Java零基础 - 动态代理
|
5月前
|
SQL 安全 Java
「滚雪球学Java」教程导航帖(更新2024.07.16)
《滚雪球学Spring Boot》是一个面向初学者的Spring Boot教程,旨在帮助读者快速入门Spring Boot开发。本专通过深入浅出的方式,将Spring Boot开发中的核心概念、基础知识、实战技巧等内容系统地讲解,同时还提供了大量实际的案例,让读者能够快速掌握实用的Spring Boot开发技能。本书的特点在于注重实践,通过实例学习的方式激发读者的学习兴趣和动力,并引导读者逐步掌握Spring Boot开发的实际应用。
86 1
「滚雪球学Java」教程导航帖(更新2024.07.16)
|
4月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
235 0
|
4月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
189 0
|
6月前
|
存储 Java 测试技术
滚雪球学Java(67):深入理解 TreeMap:Java 中的有序键值映射表
【6月更文挑战第21天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
55 2
滚雪球学Java(67):深入理解 TreeMap:Java 中的有序键值映射表
|
5月前
|
开发框架 Java Android开发
Java中的类反射与动态代理详解
Java中的类反射与动态代理详解
下一篇
无影云桌面