当前位置: 代码网 > it编程>编程语言>Java > SpringBoot项目中JDK动态代理和CGLIB动态代理的使用详解

SpringBoot项目中JDK动态代理和CGLIB动态代理的使用详解

2025年03月11日 Java 我要评论
在 spring boot 项目中,jdk 动态代理和 cglib 动态代理都是实现 aop (面向切面编程) 的重要技术。 它们的主要区别在于代理对象的生成方式和适用范围。下面详细介绍它们的使用场景

在 spring boot 项目中,jdk 动态代理和 cglib 动态代理都是实现 aop (面向切面编程) 的重要技术。 它们的主要区别在于代理对象的生成方式和适用范围。

下面详细介绍它们的使用场景:

1. jdk 动态代理 (jdk dynamic proxy)

原理:

  • jdk 动态代理是 java 提供的内置代理机制,它通过反射在运行时动态地生成代理类。
  • 代理类会实现目标类实现的接口,并将接口中的方法调用委托给一个 invocationhandler 对象来处理。
  • invocationhandler 接口负责实现具体的增强逻辑,例如日志记录、安全检查、事务管理等。

使用场景:

  • 目标类实现了接口: 如果目标类实现了接口,则 spring aop 默认使用 jdk 动态代理。
  • 简单 aop 场景: 适用于简单的 aop 场景,例如只需要对接口方法进行增强的情况。
  • 不需要代理类的构造函数: jdk 动态代理创建代理对象时,不需要调用目标类的构造函数。

优点:

  • 简单易用: jdk 动态代理是 java 内置的代理机制,使用起来比较简单。
  • 不需要第三方库: 不需要依赖第三方库。
  • 对接口友好: 代理类实现了目标类实现的接口,符合面向接口编程的思想。

缺点:

  • 必须实现接口: 目标类必须实现接口,否则无法使用 jdk 动态代理。
  • 只能代理接口方法: 只能代理接口中定义的方法,无法代理类自身定义的方法。

示例代码:

// 接口
interface myinterface {
    void dosomething();
}

// 实现类
class myclass implements myinterface {
    @override
    public void dosomething() {
        system.out.println("myclass is doing something...");
    }
}

// 调用处理器
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: " + method.getname()); // 前置增强
        object result = method.invoke(target, args); // 调用原始方法
        system.out.println("after method: " + method.getname()); // 后置增强
        return result;
    }
}

// 使用 jdk 动态代理
public class jdkdynamicproxyexample {
    public static void main(string[] args) {
        myinterface target = new myclass(); // 创建目标对象
        myinvocationhandler handler = new myinvocationhandler(target); // 创建调用处理器

        // 创建代理对象
        myinterface proxy = (myinterface) proxy.newproxyinstance(
                myinterface.class.getclassloader(),
                new class[] {myinterface.class},
                handler
        );

        proxy.dosomething(); // 调用代理对象的方法,会被拦截
    }
}

2. cglib 动态代理 (cglib dynamic proxy)

原理:

  • cglib (code generation library) 是一个强大的、高性能的代码生成库。
  • cglib 动态代理通过在运行时动态地生成目标类的子类来实现代理。
  • 代理类会继承目标类,并重写目标类的方法,在重写的方法中实现增强逻辑。
  • cglib 动态代理不需要目标类实现接口,可以直接代理类。

使用场景:

  • 目标类没有实现接口: 如果目标类没有实现接口,则 spring aop 使用 cglib 动态代理。
  • 需要代理类自身定义的方法: 需要代理类自身定义的方法,而不仅仅是接口方法。
  • 需要更高的性能: 在某些情况下,cglib 动态代理的性能可能比 jdk 动态代理更好。

优点:

  • 不需要实现接口: 目标类不需要实现接口,可以直接代理类。
  • 可以代理类自身定义的方法: 可以代理类自身定义的方法,而不仅仅是接口方法。
  • 性能较好: 在某些情况下,cglib 动态代理的性能可能比 jdk 动态代理更好。

缺点:

  • 需要第三方库: 需要依赖 cglib 库。
  • 实现复杂: cglib 动态代理的实现比较复杂,需要生成目标类的子类。
  • final 方法无法代理: 无法代理被 final 修饰的方法。
  • 对构造函数有要求: cglib 创建代理对象时,需要调用目标类的构造函数。 如果目标类没有无参构造函数,则需要手动指定构造函数。

示例代码:

import net.sf.cglib.proxy.enhancer;
import net.sf.cglib.proxy.methodinterceptor;
import net.sf.cglib.proxy.methodproxy;

import java.lang.reflect.method;

// 目标类
class myclass {
    public void dosomething() {
        system.out.println("myclass is doing something...");
    }
}

// 方法拦截器
class mymethodinterceptor implements methodinterceptor {
    @override
    public object intercept(object obj, method method, object[] args, methodproxy proxy) throws throwable {
        system.out.println("before method: " + method.getname()); // 前置增强
        object result = proxy.invokesuper(obj, args); // 调用原始方法
        system.out.println("after method: " + method.getname()); // 后置增强
        return result;
    }
}

// 使用 cglib 动态代理
public class cglibdynamicproxyexample {
    public static void main(string[] args) {
        enhancer enhancer = new enhancer(); // 创建 enhancer 对象
        enhancer.setsuperclass(myclass.class); // 设置超类
        enhancer.setcallback(new mymethodinterceptor()); // 设置回调

        myclass proxy = (myclass) enhancer.create(); // 创建代理对象

        proxy.dosomething(); // 调用代理对象的方法,会被拦截
    }
}

3. spring boot 中的 aop 配置

在 spring boot 项目中,可以通过以下方式配置 aop:

添加 aop 依赖:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-aop</artifactid>
</dependency>

编写切面类:

@aspect
@component
public class loggingaspect {

    @before("execution(* com.example.demo.service.*.*(..))")
    public void beforeadvice(joinpoint joinpoint) {
        system.out.println("before executing method: " + joinpoint.getsignature());
    }
}

配置代理方式:

  • 默认情况下,spring aop 会根据目标类是否实现了接口来选择使用 jdk 动态代理或 cglib 动态代理。
  • 可以通过 @enableaspectjautoproxy 注解的 proxytargetclass 属性来强制使用 cglib 动态代理。
@configuration
@enableaspectjautoproxy(proxytargetclass = true) // 强制使用 cglib 动态代理
public class aopconfig {
    // ...
}

总结:

特性jdk 动态代理cglib 动态代理
目标类要求必须实现接口不需要实现接口
代理对象生成方式实现接口继承类
性能一般较好
易用性简单复杂
是否需要第三方库是 (net.sf.cglib)
适用场景目标类实现了接口,简单 aop 场景目标类没有实现接口,需要代理类自身定义的方法,性能要求较高
@enableaspectjautoproxy默认值:falseproxytargetclass = true

在实际开发中,spring aop 会自动选择合适的代理方式。 如果没有特殊需求,可以使用默认配置。

如果需要强制使用 cglib 动态代理,可以设置

@enableaspectjautoproxy(proxytargetclass = true)

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com