Async和Transactional自调用不生效我查了一上午才发现是同一个坑

📅 2026/7/26 23:50:23
Async和Transactional自调用不生效我查了一上午才发现是同一个坑
我招了一个实习生让他写个异步处理任务。他用 Spring 的Async写了一个 Service怎么调都不生效。代码长这样ServicepublicclassOrderService{publicvoidprocess(LongorderId){this.sendNotification(orderId);// 希望异步执行}AsyncpublicvoidsendNotification(LongorderId){// 发通知...}}他说「我加了 Async 了啊为什么还是同步执行的」我一看就笑了——自己调自己AOP 管不了你。为什么 Async 不生效Spring 的Async、Transactional、Cacheable这些注解都是通过 AOP 代理实现的。Spring 会给 Bean 创建一个代理对象。你调用orderService.process()时实际上调用的是代理对象的方法。代理对象在方法前后织入事务、异步等逻辑。但问题来了process()方法里this.sendNotification()——这个this是原始对象不是代理对象。原始对象调用sendNotification()时Spring 根本没有机会拦截直接执行了原始方法。Transactional自调用不生效也是同一个道理。三种解法解法一注入自己最简单ServicepublicclassOrderService{AutowiredprivateOrderServiceself;// 注入代理对象publicvoidprocess(LongorderId){self.sendNotification(orderId);// 通过代理调用}AsyncpublicvoidsendNotification(LongorderId){// 现在真正异步了}}注意Spring 4.3 之后如果构造器注入会循环依赖报错用Lazy解决LazyAutowiredprivateOrderServiceself;解法二拆成两个 Service最推荐ServicepublicclassOrderService{AutowiredprivateNotificationServicenotificationService;publicvoidprocess(LongorderId){notificationService.sendNotification(orderId);}}ServicepublicclassNotificationService{AsyncpublicvoidsendNotification(LongorderId){// 独立的异步 Service}}这样结构清晰职责单一测试也好写。解法三用 ApplicationContext 拿代理ServicepublicclassOrderService{AutowiredprivateApplicationContextctx;publicvoidprocess(LongorderId){OrderServiceproxyctx.getBean(OrderService.class);proxy.sendNotification(orderId);}}这种偏 Hack能不用就不用。不只是 Async同样的坑Transactional也一样ServicepublicclassUserService{TransactionalpublicvoidcreateUser(Useruser){userMapper.insert(user);this.updateStats();// 事务不会生效}Transactional(propagationPropagation.REQUIRES_NEW)publicvoidupdateStats(){// 你以为会开启新事务其实没有}}自调用 没有事务、没有异步、没有缓存。记住这一条就够了。核心要点✅Async/Transactional自调用不生效因为this不是代理对象✅ 解法一注入自己Autowired self✅ 解法二拆成两个 Service推荐✅ 解法三ApplicationContext.getBean()不推荐✅ 不是 Bug是 Spring AOP 代理机制决定的关于作者无羡独立开发者全栈工程师专注 AI 应用与微服务架构。 分类技术复盘 个人博客 — 更多技术文章✨ 开发者福利整理 — 云服务资源汇总 软件工坊 — 我的技术分享 个人门户 — 独立开发作品全集