Java中的动态代理

简介: Java中的动态代理

1. 基本概念


Java 中的动态代理是一种在运行时创建代理对象的机制,这些代理对象在运行时动态地实现特定接口或者继承特定类,并将方法调用转发到一个处理程序(handler)。


动态代理是在程序运行时创建的,而不是在编译时创建的,因此可以根据需要动态地创建代理对象。


Java 中的动态代理通常使用 java.lang.reflect.Proxy 类来实现。通过 Proxy.newProxyInstance() 方法,你可以创建一个动态代理对象,该方法接受三个参数:类加载器、要实现的接口列表和一个 InvocationHandler 对象。

动态代理的实现基于 Java 的反射机制。在运行时,当客户端调用代理对象的方法时,这些方法调用会被转发到InvocationHandler 的 invoke() 方法中,开发者可以在 invoke() 方法中编写自定义逻辑来处理方法调用


2. 代码演示


首先我们需要有一个接口,及实现了该接口的实现类. 具体的接口和实现类略…


2.1 基于JDK动态代理


我们知道,经过代理的方法的实际执行者是 InvocationHandler 的 invoke() 方法. 我们首先定义一个实现了 InvocationHandler 接口的实现类作为我们的代理类,并实现其invoke() 方法.

public class MyInvocationHandler implements InvocationHandler {
  //  代理目标对象
    private Object target = null;

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

  //  实现增强逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + " 方法执行前.");
        Object invoke = method.invoke(target, args);
        System.out.println(method.getName() + " 方法执行后.");
        return invoke;
    }
  //  构造代理对象 并返回
    public Object getProxy(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

实现了上面的接口后,我们来实测:

public static void main(String[] args) {
  TeacherService teacherService = new TeacherServiceImpl();
  MyInvocationHandler myInvocationHandler = new MyInvocationHandler(teacherService);
  TeacherService proxy = (TeacherService) myInvocationHandler.getProxy();
  proxy.add();
}

执行代码,打印如下:

可以看到,我们的原始方法.已经被增强了.


2.2 基于CGlib的动态代理

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TestCglib {
    public static void main(String[] args) {
        //1 创建原始对象
        UserService userService = new UserService();
        /*
         2 通过cglib⽅式创建动态代理对象
         Enhancer.setClassLoader()
         Enhancer.setSuperClass()
         Enhancer.setCallback(); ---> MethodInterceptor(cglib)
         Enhancer.create() ---> 代理
         */
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TestCglib.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());
        MethodInterceptor interceptor = new MethodInterceptor() {
            //等同于 InvocationHandler --- invoke
            @Override
            public Object intercept(Object o, Method method,
                                    Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("---cglib log----");
                Object ret = method.invoke(userService, args);
                return ret;
            }
        };
        enhancer.setCallback(interceptor);
        UserService userServiceProxy = (UserService)
            enhancer.create();
        userServiceProxy.login("suns", "123345");
        userServiceProxy.register(new User());
    }
}


3. JDK代理和CGlib代理的区别


JDK 代理(也称为接口代理)和 CGLib 代理(也称为子类代理)是两种常见的代理方式,它们在实现上有一些区别:


  1. JDK 代理:
  • JDK 代理要求目标对象必须实现一个接口,代理对象和目标对象都实现了这个接口。
  • JDK 代理通过 java.lang.reflect.Proxy 类实现,动态地生成一个实现了目标接口的代理类,然后通过这个代理类创建代理对象。
  • JDK 代理只能代理实现了接口的类,无法代理未实现接口的类。
  • JDK 代理在运行时通过反射来调用目标对象的方法,因此会有一定的性能开销。


  1. CGLib 代理:
  • CGLib 代理不要求目标对象实现接口,它直接继承目标对象并重写其中的方法。
  • CGLib 代理通过字节码技术,在运行时动态地生成目标对象的子类作为代理对象。
  • CGLib 代理可以代理未实现接口的类。
  • CGLib 代理在运行时通过直接调用目标对象的方法来实现代理,因此性能上比 JDK 代理略高。


JDK 代理和 CGLib 代理各有其适用的场景:

  • 如果目标对象实现了接口,推荐使用 JDK 代理,因为它更简单、更稳定,而且在 Java 标准库中提供了支持。
  • 如果目标对象没有实现接口,或者你想要在运行时动态生成代理类,可以使用 CGLib 代理。
  • 在性能要求较高的场景下,CGLib 代理通常比 JDK 代理更适合,但需要注意 CGLib 代理对目标对象的要求较多,比如不能是 final 类型,且目标方法不能是 final 类型的。


4. 动态代理的作用


动态代理的主要用途包括:


AOP(面向切面编程):动态代理是 AOP 的核心实现机制之一,通过动态代理可以在方法执行前后进行一些横切逻辑的处理,例如日志记录、性能监控、事务管理等。

远程方法调用(RMI):动态代理可以在客户端和服务端之间进行通信,客户端通过代理对象调用远程方法,代理对象负责将方法调用序列化并发送到服务端,服务端收到请求后执行相应的方法并返回结果给客户端。

延迟加载(Lazy Loading):动态代理可以在需要时延迟加载对象,例如在访问某个对象的属性时,可以通过代理对象在需要时再去加载真实对象,从而提高程序的性能。

权限控制:动态代理可以在方法执行前进行权限验证,根据权限决定是否允许执行该方法。

总的来说,动态代理为 Java 提供了一种灵活的机制,可以在运行时动态地创建代理对象,并在代理对象中实现特定的逻辑,从而实现各种功能。


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