当前位置: 首页 > article >正文

Spring Boot代理问题

在 Spring Boot 2.x 中,AOP(面向切面编程)默认使用 CGLIB(Code Generation Library)来实现类的代理。CGLIB 代理是通过在运行时生成目标类的子类来增强目标类的方法。这种方式允许对没有实现接口的类进行代理。以下是一些原因和机制解释,说明为什么 Spring 在 AOP 中默认使用 CGLIB。

为什么默认使用 CGLIB

  1. 可用性和兼容性

    • 不依赖于接口:CGLIB 代理不需要目标类实现接口,因此它可以代理任何类,包括那些没有实现接口的类。这在某些情况下非常方便和必要。
    • Spring 选择的默认策略:由于 CGLIB 代理在更多场景中更为通用和强大,因此它被设置为默认的代理方式。
  2. 避免困惑

    • 一致性:使用 CGLIB 可以避免开发人员在决定是否需要实现接口时遇到的困惑。无论类是否实现接口,都可以使用相同的代理机制。
  3. 性能

    • 性能优化CGLIB 的性能已经过优化,足以满足大多数企业级应用的需求。虽然 JDK 动态代理在某些情况下可能略快,但差异通常对最终用户应用程序的性能没有显著影响

Spring AOP 代理机制

Spring AOP 支持两种主要的代理模式:

  1. JDK 动态代理

    • 依赖于 java.lang.reflect.Proxy,只能对实现了一个或多个接口的类进行代理。
    • 适用于所有实现接口的类。
  2. CGLIB 代理

    • 使用 net.sf.cglib.proxy 包进行代理,通过生成目标类的子类来实现方法增强。
    • 适用于没有实现接口的类,或者可以覆盖具体类的方法以实现更广泛的应用。

如何配置代理类型

虽然 Spring 默认使用 CGLIB,但开发人员可以通过配置来控制代理类型。使用 @EnableAspectJAutoProxy 注解可以指定代理方式:

  • 默认代理设置(通常是 CGLIB):
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

复制

  • 强制使用 CGLIB 代理
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig {
}

复制

  • 强制使用 JDK 动态代理(仅对实现接口的类有效):
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=false)
public class AppConfig {
}

复制

自动代理选择机制

Spring 会基于以下规则自动选择适合的代理机制:

  1. 如果目标类实现了至少一个接口,并且 proxyTargetClass 设置为 false

    • Spring 使用 JDK 动态代理。
  2. 如果目标类没有实现任何接口,或者 proxyTargetClass 设置为 true

    • Spring 使用 CGLIB 代理。

使用 AOP 的常见配置和限制

  1. 非公开方法

    • CGLIB 可以代理非公共方法(protectedpackage-private 和 private),而 JDK 动态代理只能代理公共接口的方法。
  2. 构造函数代理

    • CGLIB 在生成子类时会覆盖构造函数,而 JDK 动态代理则不涉及构造函数。

示例代码

以下是一个使用 CGLIB 代理的示例:

定义目标类(没有实现任何接口)
import org.springframework.stereotype.Component;

@Component
public class MyService {

    public void doSomething() {
        System.out.println("Doing something...");
    }
}
定义切面类
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @Before("execution(* com.example.MyService.doSomething(..))")
    public void beforeDoSomething() {
        System.out.println("Before advice is being applied...");
    }
}
配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB 代理
public class AppConfig {
}

总结

Spring Boot 2.x 默认使用 CGLIB 来实现 AOP 代理,主要是因为 CGLIB 适用于更广泛的场景,包括那些没有实现接口的类。此外,Spring 允许通过配置来选择和控制代理类型,以适应特定应用程序的需求和设计。

了解这些机制和配置选项,有助于开发人员在使用 Spring AOP 时做出更明智的选择,并确保代理行为符合预期。


http://www.kler.cn/a/384664.html

相关文章:

  • git的使用、router和route的区别以及v-show和v-if的差别
  • 深入理解 Git 及其工具的用途、使用方法与区别
  • Devops业务价值流:软件研发最佳实践
  • 【数学二】线性代数-向量-向量组的秩、矩阵得秩
  • HarmonyOS第一课——DevEco Studio的使用
  • WPF中如何简单的使用CommunityToolkit.Mvvm创建一个项目并进行 增删改查
  • SpringBoot(二)
  • Redisson分布式锁全解析
  • 技术总结(二十二)
  • 【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
  • 使用 `Celery` 配合 `RabbitMQ` 作为消息代理,实现异步任务的调度、重试、定时任务以及错误监控等功能
  • [ vulnhub靶机通关篇 ] 渗透测试综合靶场 DarkHole:1 通关详解 (附靶机搭建教程)
  • Android Studio打包时不显示“Generate Signed APK”提示信息
  • IPhone16评论自然语言处理
  • 服务器技术(一)--Linux基础入门
  • 2025年PMI-ACP敏捷项目管理认证考试时间及费用
  • angular实现list列表和翻页效果
  • ESLint 使用教程(一):从零配置 ESLint
  • MYSQL 真实高并发下的死锁
  • Swift 开发教程系列 - 第5章:集合类型
  • Docker 常用命令详解(详细版)
  • Flutter 中的那些设计模式的写法(持续更新)
  • VSCode 1.82之后的vscode server离线安装
  • ISME Comm | 机器学习和深度学习在微生物组研究中的应用
  • 牛客sql题目总结(1)
  • RK3568平台(基础篇)selinux内核安全