Spring AOP切面在CompletableFuture异步场景下@LogFailure通知失效问题
问题原因与解决方案
核心失效原因
- 内部自调用绕过Spring代理
Spring AOP基于动态代理实现,只有代理对象从外部调用标注注解的方法才会触发切面逻辑。你当前在类内部的consumerExecutor方法中直接调用this.executeSingleConsumer(),属于类内部自调用,不会经过代理对象,切面自然不会触发。 - 私有方法无法被Spring AOP拦截
你标注@LogFailure的executeSingleConsumer是private修饰的,Spring AOP默认仅对public方法生成代理,私有方法不会进入切面拦截逻辑。 - CompletableFuture异常被吞
你在allOf之后仅调用了异步回调方法thenApply,没有主动调用join()/get()阻塞获取执行结果,异步线程抛出的异常会被封装在CompletableFuture内部,不会向外抛出,@AfterThrowing通知无法感知到异常。
修复方案
- 调整方法修饰符,将
executeSingleConsumer改为public - 启用AOP代理暴露配置,在启动类的
@EnableAspectJAutoProxy注解上添加exposeProxy = true属性 - 修改异步调用逻辑,通过代理对象调用目标方法,同时主动获取异步结果触发异常抛出:
@Override public void consumerExecutor(Map<Consumer<IProcessDTO>, IProcessDTO> map, IContext context) { List<CompletableFuture<Void>> completableFutures = new ArrayList<>(); Iterator<Consumer<IProcessDTO>> consumerIterator = map.keySet().iterator(); while (consumerIterator.hasNext()) { Consumer<IProcessDTO> consumer = consumerIterator.next(); CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 通过代理对象调用方法,触发切面,替换为你自己的类名 ((你的类名) AopContext.currentProxy()).executeSingleConsumer(0, consumer, map.get(consumer)); }); completableFutures.add(future); } try { // 阻塞等待所有异步任务执行完成,异常会向外抛出 CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join(); } catch (CancellationException | CompletionException exception) { // 按需处理异常 throw exception.getCause(); } }
如果你不想修改方法调用逻辑,也可以改用AspectJ静态织入实现切面,不受代理限制,支持私有方法、内部调用的场景拦截。
内容的提问来源于stack exchange,提问作者user1526719
相关产品推荐
相关产品推荐

