Java 有没有一种方法可以选择性地禁用对测试中实体修改的审核?
我有几个实体需要审计。审计是通过使用以下JPA事件侦听器实现的Java 有没有一种方法可以选择性地禁用对测试中实体修改的审核?,java,spring-boot,jpa,spring-data-jpa,auditing,Java,Spring Boot,Jpa,Spring Data Jpa,Auditing,我有几个实体需要审计。审计是通过使用以下JPA事件侦听器实现的 public class AuditListener { @PrePersist @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW) public void setCreatedOn(Auditable auditable) { User currentUser = getCurrentUser();
public class AuditListener {
@PrePersist
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public void setCreatedOn(Auditable auditable) {
User currentUser = getCurrentUser();
Long entityId = auditable.getId();
Audit audit;
if (isNull(entityId)) {
audit = getCreatedOnAudit(currentUser);
} else {
audit = getUpdatedOnAudit(auditable, currentUser);
}
auditable.setAudit(audit);
}
@PreUpdate
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public void setUpdatedOn(Auditable auditable) {
User currentUser = getCurrentUser();
auditable.setAudit(getUpdatedOnAudit(auditable, currentUser));
}
private Audit getCreatedOnAudit(User currentUser) {
return Audit.builder()
.userCreate(currentUser)
.dateCreate(now())
.build();
}
private Audit getUpdatedOnAudit(Auditable auditable, User currentUser) {
AuditService auditService = BeanUtils.getBean(AuditService.class);
Audit audit = auditService.getAudit(auditable.getClass().getName(), auditable.getId());
audit.setUserUpdate(currentUser);
audit.setDateUpdate(now());
return audit;
}
private User getCurrentUser() {
String userName = "admin";
UserService userService = BeanUtils.getBean(UserService.class);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (nonNull(auth)) {
Object principal = auth.getPrincipal();
if (principal instanceof UserDetails) {
userName = ((UserDetails)principal).getUsername();
}
}
return userService.findByLogin(userName);
}
}
在一些测试的测试环境(单元测试,e2e)中,我希望能够手动设置审计
可能吗?我以前曾尝试用SpringAOP解决这个问题,但不幸的是没有成功。我认为,Spring AOP可以通过在切入点中使用各种组合来有选择地设置审计:
AuditListener
将执行委托给该组件的不同实现,具体取决于当前的活动配置文件
对于Spring Boot 2.1.0:
通用接口:
public interface AuditManager {
void performPrePersistLogic(Auditable auditable);
void performPreUpdateLogic(Auditable auditable);
}
JPA回调的侦听器:
@Component
@RequiredArgsConstructor
public class AuditListener {
private final AuditManager auditManager;
@PrePersist
public void setCreatedOn(Auditable auditable) {
auditManager.performPrePersistLogic(auditable);
}
@PreUpdate
public void setUpdatedOn(Auditable auditable) {
auditManager.performPreUpdateLogic(auditable);
}
}
测试环境和本地环境的公共接口实现:
@RequiredArgsConstructor
public class AuditChanger implements AuditManager {
private final UserService userService;
private final AuditService auditService;
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public void performPrePersistLogic(Auditable auditable) {
// logic here
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public void performPreUpdateLogic(Auditable auditable) {
// logic here
}
}
public class AuditNoChanger implements AuditManager {
// mostly similar
...
允许Spring根据当前活动的配置文件执行不同实现的注入的配置:
@Configuration
public class AuditConfig {
@Bean
@Profile("e2e")
public AuditManager getAuditNoChanger() {
return new AuditNoChanger();
}
@Bean
@Profile("local")
public AuditManager getAuditChanger(AuditService auditService,
CurrentUserService currentUserService) {
return new AuditChanger(auditService, currentUserService);
}
}
还需要允许在*.yml文件中重写bean:
spring:
main:
allow-bean-definition-overriding: true
由…解决
pre persist和pre update的逻辑被移动到一个单独的可注入组件,并且AuditListener
将执行委托给该组件的不同实现,具体取决于当前的活动配置文件
对于Spring Boot 2.1.0:
通用接口:
public interface AuditManager {
void performPrePersistLogic(Auditable auditable);
void performPreUpdateLogic(Auditable auditable);
}
JPA回调的侦听器:
@Component
@RequiredArgsConstructor
public class AuditListener {
private final AuditManager auditManager;
@PrePersist
public void setCreatedOn(Auditable auditable) {
auditManager.performPrePersistLogic(auditable);
}
@PreUpdate
public void setUpdatedOn(Auditable auditable) {
auditManager.performPreUpdateLogic(auditable);
}
}
测试环境和本地环境的公共接口实现:
@RequiredArgsConstructor
public class AuditChanger implements AuditManager {
private final UserService userService;
private final AuditService auditService;
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public void performPrePersistLogic(Auditable auditable) {
// logic here
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public void performPreUpdateLogic(Auditable auditable) {
// logic here
}
}
public class AuditNoChanger implements AuditManager {
// mostly similar
...
允许Spring根据当前活动的配置文件执行不同实现的注入的配置:
@Configuration
public class AuditConfig {
@Bean
@Profile("e2e")
public AuditManager getAuditNoChanger() {
return new AuditNoChanger();
}
@Bean
@Profile("local")
public AuditManager getAuditChanger(AuditService auditService,
CurrentUserService currentUserService) {
return new AuditChanger(auditService, currentUserService);
}
}
还需要允许在*.yml文件中重写bean:
spring:
main:
allow-bean-definition-overriding: true
简单地模拟/监视
UserService
(对测试上下文使用@MockBean
或简单的bean定义覆盖)怎么样?您应该能够以类似的方式覆盖创建/修改时间,使用now(clock)
而不是now()
,并注入clock
,然后使用模拟/固定瞬间覆盖测试的提供程序定义。顺便说一句,您不需要BeanUtils.getBean(UserService.class)
,Spring在JPA listenersHow中支持依赖项注入,简单地模拟/监视UserService
(使用@MockBean
或测试上下文的简单bean定义覆盖)?您应该能够以类似的方式覆盖创建/修改时间,使用now(clock)
而不是now()
,并注入clock
,然后使用模拟/固定瞬间覆盖测试的提供程序定义。顺便说一句,您不需要BeanUtils.getBean(UserService.class)
,Spring支持JPA侦听器中的依赖注入