Spring security 使用spring security AuditorAware的spring数据jpa应用程序中的StackOverflowException

Spring security 使用spring security AuditorAware的spring数据jpa应用程序中的StackOverflowException,spring-security,spring-data,spring-data-jpa,Spring Security,Spring Data,Spring Data Jpa,我的spring后端有一个非常讨厌的StackOverflowException,我需要帮助。这是不容易解决的。我真的希望能在这里找到一些帮助 我后端工作的大部分内容。我可以查询REST接口中的模型,SpringHateOAS、GET、PUT和POST操作很好地返回了这些模型。但有一个例外:当我尝试更新现有的DelegationModel时,我会遇到一个无止境的StackOverflowException 这是我的DelegetionModel.java类。请注意,该委托模型实际上没有任何带有@

我的spring后端有一个非常讨厌的StackOverflowException,我需要帮助。这是不容易解决的。我真的希望能在这里找到一些帮助

我后端工作的大部分内容。我可以查询REST接口中的模型,SpringHateOAS、GET、PUT和POST操作很好地返回了这些模型。但有一个例外:当我尝试更新现有的
DelegationModel
时,我会遇到一个无止境的StackOverflowException

这是我的
DelegetionModel.java
类。请注意,该委托模型实际上没有任何带有@CreatedBy注释的属性

@Entity
@Data
@NoArgsConstructor
@RequiredArgsConstructor(suppressConstructorProperties = true)  //BUGFIX:  https://jira.spring.io/browse/DATAREST-884
@EntityListeners(AuditingEntityListener.class)  // this is necessary so that UpdatedAt and CreatedAt are handled.
@Table(name = "delegations")
public class DelegationModel {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public Long id;

  /** Area that this delegation is in */
  @NonNull
  @NotNull
  @ManyToOne
  public AreaModel area;

  /** reference to delegee that delegated his vote */
  @NonNull
  @NotNull
  @ManyToOne
  public UserModel fromUser;

  /** reference to proxy that receives the delegation */
  @NonNull
  @NotNull
  @ManyToOne
  public UserModel toProxy;

  @CreatedDate
  @NotNull
  public Date createdAt = new Date();

  @LastModifiedDate
  @NotNull
  public Date updatedAt = new Date();

}
如中所述,我实现了必要的AuditorAware接口,该接口从SQL DB加载用户模型。我原以为只有在具有用
@CreatedBy
注释的字段的模型中才会调用此AuditorAware接口

@Component
public class LiquidoAuditorAware implements AuditorAware<UserModel> {
  Logger log = LoggerFactory.getLogger(this.getClass());  // Simple Logging Facade 4 Java

  @Autowired
  UserRepo userRepo;    

  @Override
  public UserModel getCurrentAuditor() {
      Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
      if (authentication == null || !authentication.isAuthenticated()) {
        log.warn("Cannot getCurrentAuditor. No one is currently authenticated");
        return null;
      }
      User principal = (org.springframework.security.core.userdetails.User) authentication.getPrincipal();
      UserModel currentlyLoggedInUser = userRepo.findByEmail(principal.getUsername());   // <<<<======= (!)
      return currentlyLoggedInUser;
    } catch (Exception e) {
      log.error("Cannot getCurrentAuditor: "+e);
      return null;
    }
  }
}
由于某种原因,我看不出来,这实际上调用了上面的AuditorAware实现。现在的问题是,我的LqiuidoAuditorAware实现在无休止的循环中一次又一次地被调用。似乎LiquidoAuditorAware.java中的UserModel查询再次调用了LiquidoAuditorAware。(这是不寻常的,因为这只是来自DB的读取操作。)

这是你的电话号码

所有代码都可以在此找到


我真的需要任何帮助。我在黑暗中搜索:-)

您看到这种行为的原因是,
AuditorAware
实现是从JPA
@PrePersist
/
@PreUpdate
回调中调用的。现在通过调用
findByEmail(…)
发出一个查询,这将再次触发脏检测,从而触发刷新,从而调用回调

建议的解决方法是将
UserModel
的实例保留在Spring Security
User
实现中(在
UserDetailsService
在身份验证时查找实例时进行查找),这样就不需要额外的数据库查询


另一个(不太推荐的)解决方法是将
EntityManager
注入到
AuditorAware
实现中,在查询执行之前调用
setFlushMode(FlushModeType.COMMIT)
,然后将其重置为
FlushModeType.AUTO
,这样查询执行时不会触发刷新。

非常感谢您的快速回答!我有点高兴,我最初的猜测是正确的,AuditorAware内部的查询才是问题所在。但我没有看到解决办法。我会这么做的。仅供参考:刚刚在一分钟前发现了一个非常类似的问题:Oliver,这仍然是推荐的方法,还是在spring security或spring data jpa的更高版本中已经修复了?
@RestController
@RequestMapping("/liquido/v2/users")
public class UserRestController {

  [...]

  @RequestMapping(value = "/saveProxy", method = PUT, consumes="application/json")
  @ResponseStatus(HttpStatus.CREATED)
  public @ResponseBody String saveProxy(
                      @RequestBody Resource<DelegationModel> delegationResource,
                      //PersistentEntityResourceAssembler resourceAssembler,
                      Principal principal)            throws BindException
  {
    [...]
    DelegationModel result = delegationRepo.save(existingDelegation);
    [...]
  }

  [...]         

}