Spring Boot 2.7+ 中,自定义 JPA Repository 实现类因直接注入自身接口(如 Publications)导致启动时 Bean 循环依赖;通过 @Lazy 延迟加载被注入的 Repository 接口可安全打破循环,这是符合 Spring 设计规范的标准解法。
spring boot 2.7+ 中,自定义 jpa repository 实现类因直接注入自身接口(如 `publications`)导致启动时 bean 循环依赖;通过 `@lazy` 延迟加载被注入的 repository 接口可安全打破循环,这是符合 spring 设计规范的标准解法。
在 Spring Data JPA 中,当您通过自定义实现类(如 PublicationsImpl)扩展 Repository 接口功能时,若该实现类内部又直接 @Autowired 注入了同名的 Repository 接口(Publications),就会在 ApplicationContext 初始化阶段触发构造/装配循环依赖:
- PublicationsImpl 是一个 @Repository Bean,需在启动时实例化;
- 其构造或字段注入依赖 Publications;
- 而 Publications 本身是 Spring Data 自动生成的代理 Bean,其创建过程可能间接依赖 PublicationsImpl(例如通过 @EnableJpaRepositories 扫描到自定义实现并尝试注入),从而形成闭环。
✅ 正确且推荐的解决方案是使用 @Lazy 注解于注入点:
@Repository
public class PublicationsImpl implements PublicationsCustom {
@Autowired
@Lazy // 关键:延迟初始化 Publications 代理 Bean
private Publications publications;
public Foo someCustomOperation(String id, LocalDate xyz) {
var myStuff = publications.findById(id).orElseThrow();
// ... 业务逻辑
var moreStuff = publications.findBySomeComplexQuery(myStuff, xyz);
return new Foo(...);
}
}
⚠️ 注意事项:
- @Lazy 必须作用于 注入字段(或构造函数参数/Setter 方法),而非 @Repository 接口本身——接口本身不能加 @Lazy,它只是 Spring 生成的代理契约;
- 不要对 PublicationsImpl 类加 @Lazy(如 @Lazy @Repository),否则整个自定义实现将延迟初始化,可能导致其他依赖它的 Bean 启动失败或行为不可预期;
- 此方案完全兼容 Spring Boot 2.7+ 的严格循环依赖检测(默认 spring.main.allow-circular-references=false),无需降级配置;
- 若项目中存在多个类似自定义实现,每个循环注入点均需单独标注 @Lazy。
? 补充建议:更优雅的长期设计是避免在自定义实现中反向注入 Repository 接口。可考虑:
- 将共用查询逻辑提取为 @Query 或 @NamedEntityGraph,由 Spring Data 自动处理;
- 使用 JpaRepository 的 EntityManager 或 @PersistenceContext 直接操作底层 JPA 资源;
- 通过 Service 层协调 Publications 与 PublicationsImpl 的调用,而非让实现类依赖接口。
@Lazy 不是“权宜之计”,而是 Spring 官方明确支持的、解决此类“接口 ↔ 实现”双向依赖的标准模式。











