Есть ли способ выборочно отключить аудит для изменений объекта в тестах? - PullRequest
0 голосов
/ 20 сентября 2019

У меня есть несколько сущностей, которые необходимо проверить.Аудит реализуется с помощью следующего прослушивателя событий JPA.

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) для некоторых тестов я хочу иметь возможность установить аудит вручную.

Это возможно?Ранее я пытался решить эту проблему с помощью Spring AOP, но, к сожалению, безуспешно.Я думаю, что Spring AOP может позволить выборочно установить аудит с помощью различных комбинаций в pointcut:

Существует ли способ выборочного задания аудита с использованием функций JPA?

1 Ответ

0 голосов
/ 23 сентября 2019

Решено как было предложено от Naros .

Логика 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);
    }
}

Также необходимо разрешить переопределение bean-компонентов в файле * .yml:

spring:
  main:
    allow-bean-definition-overriding: true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...