Either pull the method up to an interface or switch to CGLIB proxies by

编程入门 行业动态 更新时间:2024-10-04 21:22:03

Either pull the method up to an <a href=https://www.elefans.com/category/jswz/34/1765416.html style=interface or switch to CGLIB proxies by"/>

Either pull the method up to an interface or switch to CGLIB proxies by

问题背景

公司使用的是springboot项目,在启动类中排除了事务管理器相关的配置类,如下

@SpringBootApplication(scanBasePackages = "com.sf.*",exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})

同时,还引入了atomikos数据源的maven依赖。

  <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jta-atomikos</artifactId></dependency>

当前,项目中FalconGrpHostService接口的实现类为FalconGrpHostServiceImpl,后者有个方法加了TransactionalEventListenerAsync注解,但接口中无此方法,只在实现类中存在。
方法如下:

项目启动本来一直没问题的,结果某次不小心去掉了atomikos数据源的依赖,启动时就报如下错

 Need to invoke method 'refreshHostGroupAlarmTarget' declared on targetclass 'FalconGrpHostServiceImpl', but not found in any interface(s) ofthe exposed proxy type. Either pull the method up to an interface orswitch to CGLIB proxies by enforcing proxy-target-class mode in yourconfiguration.

问题分析

根据对spring源码的理解,猜测原因是FalconGrpHostService接口中没有方法导致,流程如下

spring实例化bean后,收集有TransactionalEventListener注解的方法时,会先判断所在类是否有此方法。
此时,发现所在类为spring生产的jdk代理类,于是在接口中找方法,但实际接口中无此方法,所以报错。

虽然知道了原因,但是有几个疑问让人困惑

首先,为什么之前不报错,而我把atomikos依赖去掉后就报错?是不是之前用的cglib,后来用的jdk?
其次,项目启动类已经通过@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)设置了强制用cglib,即使我把atomikos去掉,为什么还会生产jdk代理

断点分析

为了解决上述困惑,我借助断点来一步步对源码进行做了分析,最终观察到的结果如下:

- 当引入atomikos依赖时

1.首先实例化controller
2.由于controller注入了该接口,于是实例化FalconGrpHostService接口
3.遍历BeanPostProcessor
4.AnnotationAwareAspectJAutoProxyCreator获取到了事务相关的advisor,由于proxyTargetClass为true,于是产生cglib代理

- 当去掉atomikos依赖时

1.首先实例化controller
2.由于controller注入了该接口,于是实例化FalconGrpHostService接口
3.遍历BeanPostProcessor
4.AnnotationAwareAspectJAutoProxyCreator此时未获取到事务的advisor但是AsyncAnnotationBeanPostProcessor获取到了(因为方法有加Async注解),于是会通过如下方法产生代理

在这一步中,AsyncAnnotationBeanPostProcessor也会使用@EnableAsync中的proxyTargetClass属性值来决定生成什么类型的代理,但是目前项目中并没有设置,所以该属性值默认为false
于是,最终产生了jdk代理而不是cglib代理

根本原因

至此,我们可以回答刚才提到的两个疑问:

为什么之前不报错,而我把atomikos依赖去掉后就报错?是不是之前用的cglib,后来用的jdk?————————是的,后来用的jdk代理
项目启动类已经通过@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)设置了强制用cglib,即使我把atomikos去掉,为什么还会生产jdk代理?————————因为@EnableAsync中的proxyTargetClass属性值默认为false

解决方案

如果非要去掉atomikos依赖,那么有以下解决方案

1.设置@EnableAsyncproxyTargetClass为true,这样即使去掉了atomikos依赖,由于最终生成cglib代理,所以也能获取到TransactionalEventListener注解的方法
2.不设置@EnableAsyncproxyTargetClass属性,直接将实现类的方法也定义在接口中即可。

更多推荐

Either pull the method up to an interface or switch to CGLIB proxies by

本文发布于:2024-02-28 09:03:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1768718.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:interface   method   pull   proxies   CGLIB

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!