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

Spring Boot 3+自注入实现代理与事务:循环依赖问题求解

Spring自引用触发事务:避免循环依赖的解决方案

问题背景

要在服务类中创建自引用,通过Spring代理触发@Transactional事务行为,同时满足java:S6809规范(类内部直接调用带@Async/@Transactional的方法会绕过代理,导致注解失效)。

编写的代码如下:

@RequiredArgsConstructor
public class Service {
  @Lazy private final Service self;

  public void foo() {
    self.bar();
  }

  @Transactional
  public void bar() {
    // do some transactional stuff
  }
}

启动时触发循环依赖错误:

The dependencies of some of the beans in the application context form a cycle:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

已尝试@Lazy注解及Lombok配置lombok.copyableAnnotations += org.springframework.context.annotation.Lazy,但问题未解决,询问是否只能通过开启循环引用配置解决。

无需开启循环引用的解决方法

1. 实现ApplicationContextAware获取代理实例

让服务类实现ApplicationContextAware接口,在初始化完成后从上下文获取自身代理对象,完全规避构造注入的循环依赖:

@Service
public class Service implements ApplicationContextAware {
    private Service self;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.self = applicationContext.getBean(Service.class);
    }

    public void foo() {
        self.bar();
    }

    @Transactional
    public void bar() {
        // do some transactional stuff
    }
}

2. 改用@Autowired+@Lazy字段注入

放弃构造注入,改用字段注入并结合@Lazy,确保类被Spring管理(添加@Service注解):

@Service
public class Service {
    @Autowired
    @Lazy
    private Service self;

    public void foo() {
        self.bar();
    }

    @Transactional
    public void bar() {
        // do some transactional stuff
    }
}

构造注入时@Lazy可能因Lombok注解传递问题失效,字段注入的延迟加载能有效打破循环依赖。

3. 拆分业务到独立服务

若业务允许,将带事务的方法拆分到独立子服务,直接注入调用,从根源避免自引用需求:

@Service
public class Service {
    private final SubService subService;

    public Service(SubService subService) {
        this.subService = subService;
    }

    public void foo() {
        subService.bar();
    }
}

@Service
public class SubService {
    @Transactional
    public void bar() {
        // do some transactional stuff
    }
}

构造注入+@Lazy失效的原因

Lombok的@RequiredArgsConstructor默认不会将字段上的@Lazy复制到构造器参数,即便配置了lombok.copyableAnnotations也可能因版本或配置生效问题失效。可手动编写构造器验证:

@Service
public class Service {
    private final Service self;

    public Service(@Lazy Service self) {
        this.self = self;
    }

    // 方法省略
}

若手动添加参数级@Lazy解决问题,说明是Lombok配置未生效;若仍失败,建议改用前两种方案。


内容的提问来源于stack exchange,提问作者dorian.naa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:10:24