前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java避坑指南:Spring AOP避坑之对象逸出导致的并发安全问题 及 AOP顺序导致的业务逻辑问题

Java避坑指南:Spring AOP避坑之对象逸出导致的并发安全问题 及 AOP顺序导致的业务逻辑问题

作者头像
崔认知
发布2023-06-20 12:03:32
5840
发布2023-06-20 12:03:32
举报
文章被收录于专栏:nobody

简介


在《Java并发编程实战》原作名: Java Concurrency in Practice 3.2与3.5章节介绍了对象不合理的逸出导致的并发安全问题及如何安全发布对象。在spring框架流行的今天,AOP很容易导致对象逸出带来并发安全问题

由于经常使用AOP技术来统一处理某些功能性的需求,很容易导致AOP之间的顺序不正确带来一些业务异常现象

AOP导致对象逸出的并发安全问题


AOP导致对象逸出主要涉及到入参和返回值对象的逸出。这些对象的逸出主要涉及异步线程的引入及缓存

如果开启了异步线程,主线程和异步线程有一方对此对象做了修改,那就会导致并发安全问题。

如果缓存了对象,对象就会被多个线程访问,如果有一个线程对对象做了修改,那也会导致并发安全问题。

AOP顺序不正确带来一些业务异常现象


由于AOP技术的侵入性不是非常强,所以被经常用来统一处理某些功能性的需求。

比如分布式锁使用注解+AOP实现,当遇到分布式锁注解与@Transaction注解一起使用时,如果分布式锁的处理逻辑在@Transaction的处理逻辑内,导致事务还没处理完,分布式锁就被释放,会导致业务数据的不正确性。所以必须保证分布式锁AOP优先与事务AOP执行。【微信公众号:认知科技技术团队】

比如引入spring-retry,使用注解@Retryable,方便我们重试,除了重试考虑幂等性外,当@Retryable与@Transaction同时共同作用在某个方法上时,如果事务的拦截器先于重试的拦截器先执行,由于快照读快照读会生成一个ReadView(读视图),InnoDB引擎在默认隔离级别可重复读情况下,第一次普通的select生成ReadView,在事务提交之前一直不变,这就导致在@Transaction事务内执行@Retryable重试是无效的。所以@Retryable的执行必须先于@Transaction

见:

https://github.com/spring-projects/spring-retry/issues/22

及spring官方文档:

比如每个项目接入的数据库资源比较多时,我们会选择动态切数据源的方式来使用。(动态数据源我们一般实现org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource)。当切数据源AOP与@Transaction同时出现时,如果没有在事务AOP执行之前切数据源,动态切数据源会失败,这个主要涉及到事务的执行机制及ThreadLocal实现原理有关,此不再谈论。所以动态切数据源的AOP执行顺序必须优先事务AOP执行

感兴趣的可以去了解下https://github.com/baomidou/dynamic-datasource-spring-boot-starter。

小结


AOP技术在应用中非常常见,不过也会引入一些坑:

1、AOP导致对象逸出的并发安全问题

主要涉及到入参和返回值对象的逸出。这些对象的逸出主要涉及异步线程的引入及缓存。

2、AOP顺序不正确带来一些业务异常现象

主要谈到了常见的:分布式锁AOP优先与事务AOP执行、@Retryable的执行必须先于@Transaction、动态切数据源的AOP执行顺序必须优先事务AOP执行等。

当然遇到的坑还会有,后面有时间在讨论。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档