Spring-boot EntityListener,application context中部分bean的依赖形成一个循环
Spring-boot EntityListener, The dependencies of some of the beans in the application context form a cycle
我在以下设计中面临依赖循环(摘自 here)。
我有 2 个实体 Post 和 PostLog。创建 Post 后,我也想将其保存在 PostLog 中。因此创建了侦听器并将其应用于“Post”实体。实体 Post 和 PostLog 也都使用 spring-boot “AuditingEntityListener”,但为了简单起见,我不在此处添加该代码。
我的实体和监听器结构 -
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "post")
@EntityListeners({AuditingEntityListener.class, PostLogListener.class})
public class Post extends Auditable<String> {
...
}
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "post_log")
@EntityListeners(AuditingEntityListener.class)
public class PostLog extends Auditable<String> {
...
}
@Component
@RequiredArgsConstructor
public class PostLogListener {
private final PostLogRepository repo;
@PostPersist
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logEvent(final Post post) {
PostLog log = createLog(post); // implementation is omitted here for keeping short
repo.save(log);
}
}
@Repository
public interface PostLogRepository extends CrudRepository<PostLog, Long> {}
我收到错误 -
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| entityManagerFactory defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]
↑ ↓
| com.example.listener.PostLogListener
↑ ↓
| postLogRepository defined in com.example.repository.PostLogRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
↑ ↓
| (inner bean)#53c2dd3a
└─────┘
我做了一些研究,但找不到合适的解决方案。
使用惰性初始化解决循环依赖。为此,您需要自己创建构造函数以注入 spring bean 并使用 @Lazy (org.springframework.context.annotation.Lazy)
@Component
public class PostLogListener {
private final PostLogRepository repo;
public PostLogListener(@Lazy PostLogRepository repo) {
this.repo = repo;
}
@PostPersist
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logEvent(final Post post) {
PostLog log = createLog(post); // implementation is omitted here for keeping short
repo.save(log);
}
}
Note - This is required if any of the injected beans depends on the
EntityManager. Spring Data repositories depend on EntityManager, so
any bean having a repository or a direct entityManager will make a
circle.
我在以下设计中面临依赖循环(摘自 here)。
我有 2 个实体 Post 和 PostLog。创建 Post 后,我也想将其保存在 PostLog 中。因此创建了侦听器并将其应用于“Post”实体。实体 Post 和 PostLog 也都使用 spring-boot “AuditingEntityListener”,但为了简单起见,我不在此处添加该代码。
我的实体和监听器结构 -
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "post")
@EntityListeners({AuditingEntityListener.class, PostLogListener.class})
public class Post extends Auditable<String> {
...
}
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "post_log")
@EntityListeners(AuditingEntityListener.class)
public class PostLog extends Auditable<String> {
...
}
@Component
@RequiredArgsConstructor
public class PostLogListener {
private final PostLogRepository repo;
@PostPersist
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logEvent(final Post post) {
PostLog log = createLog(post); // implementation is omitted here for keeping short
repo.save(log);
}
}
@Repository
public interface PostLogRepository extends CrudRepository<PostLog, Long> {}
我收到错误 -
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| entityManagerFactory defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]
↑ ↓
| com.example.listener.PostLogListener
↑ ↓
| postLogRepository defined in com.example.repository.PostLogRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
↑ ↓
| (inner bean)#53c2dd3a
└─────┘
我做了一些研究,但找不到合适的解决方案。
使用惰性初始化解决循环依赖。为此,您需要自己创建构造函数以注入 spring bean 并使用 @Lazy (org.springframework.context.annotation.Lazy)
@Component
public class PostLogListener {
private final PostLogRepository repo;
public PostLogListener(@Lazy PostLogRepository repo) {
this.repo = repo;
}
@PostPersist
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logEvent(final Post post) {
PostLog log = createLog(post); // implementation is omitted here for keeping short
repo.save(log);
}
}
Note - This is required if any of the injected beans depends on the EntityManager. Spring Data repositories depend on EntityManager, so any bean having a repository or a direct entityManager will make a circle.