You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring AOP切JPA Repository触发循环导致saveAndFlush无法入库

问题根源

你当前的切点匹配规则覆盖了com.hm包下所有repository层的public方法,而你在切面逻辑中调用的OperateLogRepository的findAll、saveAndFlush方法本身也符合切点规则,会再次触发AOP切面逻辑,形成无限递归调用,最终抛出栈溢出异常触发事务回滚,所以数据无法插入数据库。

解决方案

你可以根据业务场景选择以下任意一种方案:

  • 方案1:调整切点表达式,直接排除OperateLogRepository的匹配
    修改你的切点规则,增加排除逻辑,如下:

    // 路径替换为你项目中OperateLogRepository的实际包路径
    @Pointcut("execution(public * com.hm..repository..*(..)) && !within(com.hm.repository.OperateLogRepository+)")
    public void http() {
    }
    

    表达式中!within表示排除指定类下的所有方法,末尾的+包含Spring Data JPA为Repository接口生成的动态代理实现类,确保排除规则生效。

  • 方案2:通过自定义注解标记需要切面增强的方法,避免无差别匹配

    1. 首先自定义一个标记注解,比如@LogPointcut
    2. 调整切点规则,只匹配带有该注解的类或方法:
    @Pointcut("execution(public * com.hm..repository..*(..)) && @within(com.hm.annotation.LogPointcut)")
    public void http() {
    }
    
    1. 给需要做日志增强的Repository类加上@LogPointcut注解,OperateLogRepository不加即可,这种方式灵活度更高,后续需要新增不需要切入的Repository时不需要修改切点表达式。
  • 方案3:在切面逻辑中增加判断,跳过OperateLogRepository的方法增强
    在doAround方法最开头加入类名判断,匹配到OperateLogRepository的调用时直接执行原方法不做增强:

    @Around("http()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 判断当前调用的目标类是否为OperateLogRepository的实现
        if (pjp.getTarget() instanceof OperateLogRepository) {
            return pjp.proceed();
        }
        // 原有逻辑不变
        if (operateLogRepository!=null) {
            List<OperateLog> operateLogList = operateLogRepository.findAll();
            OperateLog operateLog = new OperateLog();
            operateLog.setId("123");
            operateLogRepository.saveAndFlush(operateLog);
        }
        return pjp.proceed();
    }
    

    这种方案改造成本最低,不需要修改切点规则,适合临时快速修复问题。

内容的提问来源于stack exchange,提问作者dean gao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 17:54:03