spring aop报Cannot subclass final class class $Proxy145

本文解决Spring框架中使用AOP拦截final类导致的CGLIB代理错误,包括检查final类的使用、配置proxyTargetClass属性以强制代理目标类以及避免类的多次代理。
部署运行你感兴趣的模型镜像

类似以下的spring错误信息:

org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy145]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy145

 

解决问题的检查点:

1、需要AOP拦截的类是否是final的,final类不可使用CGLIB来代理。

2、是否在给BEAN配AOP的时候强制使用CGLIB,如果是则可指定proxyTargetClass属性以让spring强制代理目标类。

3、类是否被多次代理了,如果类被多次代理过,则第二次进行代理的时候拿到的是第一次代理后的对象,这个对象是个final形式的,所以会出现这个错误。

 

基于第三点要注意,类是否被多次代码不紧紧取决于类是否被配置了多次AOP,如果类实现了某个接口,则还要看类实现的接口是否被aop拦截过。如果类实现了接口且接口也被AOP拦截了,则很可能出现上面的错误(是否出错取决于AOP代理执行的顺序)。

您可能感兴趣的与本文相关的镜像

HunyuanVideo-Foley

HunyuanVideo-Foley

语音合成

HunyuanVideo-Foley是由腾讯混元2025年8月28日宣布开源端到端视频音效生成模型,用户只需输入视频和文字,就能为视频匹配电影级音效

### 无法继承 `final` 类时的解决方案 在使用 CGLIB 或动态代理时,如果目标类或方法被声明为 `final`,则会导致代理失败,抛出 `Cannot subclass final class` 异常。这是因为 CGLIB 通过生成子类来实现代理机制,而 `final` 类无法被继承,从而无法创建代理对象[^1]。 为了解决这个问题,可以从以下几个方面进行优化和调整: #### 1. 避免对 `final` 类或方法进行增强 最直接的解决方式是调整切点表达式,确保不拦截 `final` 类或方法。例如,可以通过限定包路径或类名来缩小拦截范围: ```java @Pointcut("execution(* com.example.service..*(..))") public void printLog() {} ``` 该方式通过切点表达式控制拦截范围,避免对 `final` 类进行代理,从而规避异常[^1]。 #### 2. 使用接口代理替代 CGLIB 代理 Spring AOP 默认在目标类实现接口时使用 JDK 动态代理,而在没有接口时使用 CGLIB。为了避免 CGLIB 对 `final` 类的限制,可以为被代理类定义接口,并确保使用 JDK 动态代理机制。 ```java public interface MyService { void doSomething(); } public class MyServiceImpl implements MyService { public void doSomething() { // 业务逻辑 } } ``` 这样即使方法被声明为 `final`,也不会影响代理的生成,因为 JDK 动态代理不依赖继承机制。 #### 3. 避免在配置类中使用 `final` 关键字 Spring Boot 的自动配置类(如 `AutoConfigurationPackages`)通常被声明为 `final`,因此如果尝试对其增强,会触发 `Cannot subclass final class` 异常。为了避免此类问题,应确保不拦截 Spring Boot 的内部类或配置类。 #### 4. 使用 AspectJ 替代 Spring AOP Spring AOP 在运行时基于代理机制实现,而 AspectJ 是编译时织入的 AOP 框架,它不依赖继承或接口,而是通过修改字节码直接织入增强逻辑。因此,即使目标类或方法被声明为 `final`,AspectJ 仍然可以正常进行增强。 ```java @Aspect public class LoggingAspect { @Around("execution(* com.example.service..*(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { // 增强逻辑 return joinPoint.proceed(); } } ``` 这种方式适用于对 `final` 类或方法进行增强的场景。 #### 5. 修改目标类设计,避免使用 `final` 关键字 如果业务代码允许,可以考虑移除 `final` 关键字,以支持 CGLIB 代理机制。例如: ```java public class MyService { public void doSomething() { // 原本是 final 方法 } } ``` 此方式适用于可以修改源码的情况,但在某些设计模式(如不可变对象)中可能不适用。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值