JDK动态代理和CGLIB动态代理

宅哥聊构架 后端 2025-02-27

JDK动态代理和CGLIB动态代理

Java动态代理是一种在运行时创建代理对象的技术,它允许开发者在不修改目标类代码的情况下,通过代理类对目标类的实例方法进行增强或拦截。动态代理的核心价值在于能够在程序运行阶段动态地生成一个实现了预定义接口的新类,这个新类就是所谓的“代理类”。

在Java中,有两种主要的实现方式:

  1. JDK动态代理

    • JDK动态代理是Java SE API内置的一种动态代理机制,它通过java.lang.reflect.Proxy类和InvocationHandler接口来实现。
    • 使用JDK动态代理,目标类必须实现至少一个接口。代理类会继承Proxy类并实现与目标类相同的接口,这样代理类就能替代目标类成为接口的实现者。
    • 当调用代理类的方法时,实际会调用到InvocationHandler接口中的invoke方法,在invoke方法内部可以添加额外的功能,如方法执行前后的附加逻辑、权限控制、日志记录等,然后调用目标对象的实际方法。
  2. CGLIB动态代理

    • CGLIB(Code Generation Library)是一个第三方库,它通过字节码技术为没有实现接口的目标类生成子类作为代理类。
    • CGLIB代理能够代理任何未实现接口的类,因为它是通过继承的方式生成一个目标类的子类,重写父类的方法并在方法中加入增强逻辑。
    • 这种方式更加灵活,但要求代理的目标类不能声明为final类,并且方法也不能是final方法,否则无法被CGLIB成功继承和重写。

无论是哪种动态代理方式,其目的都是为了在目标方法执行前后增加额外的行为,或者改变原有的行为,以满足特定的需求,例如AOP(面向切面编程)框架中的事务管理、性能监控、日志记录等功能。

1.JDK动态代理

以下是一个简单的JDK动态代理示例,假设我们有一个接口Sellable和它的实现类RealEstate。在这个例子中,我们将创建一个动态代理来记录每次调用卖房方法时的日志信息。

首先,定义业务接口:java

代码解读
复制代码
// 业务接口:买卖物品 public interface Sellable { void sell(String item); void buy(String item); }

然后,实现这个接口的实体类:java

代码解读
复制代码
// 接口的实现类:房地产公司 public class RealEstate implements Sellable { @Override public void sell(String item) { System.out.println("实际销售房源: " + item); } @Override public void buy(String item) { System.out.println("实际购买房源: " + item); } }

接下来,创建一个InvocationHandler实现类,用于处理对代理对象方法的调用:java

代码解读
复制代码
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LoggingInvocationHandler implements InvocationHandler { // 被代理的对象引用 private final Sellable target; public LoggingInvocationHandler(Sellable target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法调用前的操作:记录日志 System.out.println("开始销售房源操作..."); // 调用目标对象的方法,并返回结果 Object result = method.invoke(target, args); // 方法调用后的操作:再次记录日志 System.out.println("完成销售房源操作."); return result; } }

最后,通过Proxy类创建并使用动态代理:java

代码解读
复制代码
public class Main { public static void main(String[] args) { // 实例化真实对象 Sellable realEstate = new RealEstate(); // 创建代理对象,并将真实对象传给InvocationHandler // 这块代码是动态代理的精髓 Sellable proxy = (Sellable) Proxy.newProxyInstance( Sellable.class.getClassLoader(), new Class<?>[]{Sellable.class}, new LoggingInvocationHandler(realEstate) ); // 现在调用的是代理对象的方法,但会触发InvocationHandler的逻辑 proxy.sell("豪华别墅"); proxy.buy("大平层"); // 输出: // 开始销售房源操作... // 实际销售房源: 豪华别墅 // 完成销售房源操作. } }

在这个例子中,当客户端代码通过代理对象调用sell方法时,实际上会执行LoggingInvocationHandler中的invoke方法,在该方法内部先进行日志记录,然后调用实际对象的方法完成销售动作,最后再记录一次日志。这就是JDK动态代理的基本应用。


转载来源:https://juejin.cn/post/7374343669208612873

Apipost 私有化火热进行中

评论