Spring WebFlux中协程suspend方法加@Transactional注解报错如何解决
问题原因
- 核心触发点为Spring事务代理与suspend函数反射调用的不兼容:当服务层suspend函数添加
@Transactional注解后,Spring会为该服务类生成CGLIB动态代理对象来实现事务逻辑。你自定义的asHandlerFunction桥接方法中使用的反射调用逻辑,是基于原服务类的方法元数据去调用代理对象,二者类型不匹配,就会抛出object is not an instance of declaring class异常。 - 版本兼容问题:如果你的Spring Framework版本低于5.3(对应Spring Boot版本低于2.4),本身就不原生支持suspend函数的
@Transactional注解,也会触发同类调用异常。 - 隐式事务失效风险:你当前在arrow-kt的
either代码块中抛出RuntimeException,either默认会将异常捕获转换为Either.Left返回值,若没有配置事务的回滚规则,就算注解正常生效,也可能出现异常不触发事务回滚的问题。
解决方案
方案1(推荐):替换自定义桥接方法为官方协程路由
Spring 5.3+ 已经原生支持协程路由,直接使用coRoute定义路由即可,完全规避自定义反射逻辑与代理类的冲突:
@Bean fun router(...): RouterFunction<ServerResponse> { return coRoute { POST("...") { request -> createNewOneSecondResolutionSession(request) } } }
删除原有自定义的asHandlerFunction方法即可。
方案2:适配事务与arrow-kt的返回规则
- 确认Spring Boot版本 >= 2.4,保证suspend函数的事务注解可以被正常识别。
- 调整
@Transactional注解的回滚规则,保证所有异常场景都可以触发回滚:
@Transactional("tm1", rollbackFor = [Throwable::class]) suspend fun theFun( a: A, b: B ): Either<Error, Result> = either { // 原有业务逻辑 }
如果需要返回Either.Left时也触发回滚,可以在方法执行结束后判断返回值,手动抛出业务异常,或者自定义事务切面统一处理Either.Left的回滚逻辑。
方案3(可选,仅当必须保留自定义桥接方法时使用)
修改asHandlerFunction的反射调用逻辑,使用Spring官方提供的CoroutinesUtils.invokeSuspendingFunction工具类执行suspend方法调用,该工具类原生适配Spring代理对象,不会出现类型不匹配问题。
内容的提问来源于stack exchange,提问作者tzortzik
相关产品推荐
相关产品推荐

