
📘Spring에서 주 로직 실패와 무관하게 로그를 남기는 방법
@Async — 비동기 방식코드예시
@Service
public class LogService {
@Async
public void saveLog(LogRequest request) {
logRepository.save(request.toEntity());
}
}
@Transactional
public void changeUserRole(...) {
...
logService.saveLog(...); // 주 트랜잭션과 분리되어 실행됨
...
user.updateRole(newRole); //주 로직
}
주의할 점
@EnableAsync 설정 필요REQUIRES_NEW - 새 트랜잭션 방식@Transactional(propagation = Propagation.REQUIRES_NEW) 사용코드 예시
@Service
public class LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(LogRequest request) {
logRepository.save(request.toEntity());
}
}
@Transactional
public void changeUserRole(...) {
...
try {
logService.saveLog(...); // 실패해도 메인 트랜잭션에 영향 없음
} catch (Exception e) {
log.error("로그 저장 실패", e);
}
...
}
주의할 점
REQUIRES_NEW 방식 사용할 땐 import org.springframework.transaction.annotation.Transactional이 맞는지 확인@Async는 단일 메서드 비동기처리에 적합@Async + @EventListener 조합으로 비동기 분리 처리와 유지보수성 향상이 가능코드예시
@Configuration
@EnableAsync
public class AsyncConfig {
}
@Service
@RequiredArgsConstructor
public class UserService {
private final ApplicationEventPublisher publisher;
@Transactional
public void changeUserRole(...) {
...
publisher.publishEvent(...);
...
user.updateRole(userRole); //주 로직
}
}
@Component
@RequiredArgsConstructor
public class LogEventHandler {
private final LogService logService;
@Async
@EventListener
public void addLog(LogRequest request){
logService.addLog(request);
}
}
주의할점
@Async가 작동하려면 클래스에 @EnableAsync가 선언되어 있어야 한다.@SpringBootApplication에 같이 선언하거나 별도 설정 파일에서 지정해준다.| 항목 | @Async | REQUIRES_NEW | @EventListener + @Async |
|---|---|---|---|
| 실행 방식 | 비동기 (멀티스레드) | 동기 (새 트랜잭션) | 비동기 (멀티스레드 + 이벤트 기반) |
| 트랜잭션 분리 | 기존 트랜잭션 영향받음 | 명시적 분리 | 핸들러에서 분리 가능 |
| 성능 | 빠름 | 보통 | 빠름 (확장성↑) |
| 예외 제어 | 어렵고 로그 유실 위험 | 쉬움 | 적절히 제어 가능 (로직 분리) |
| 유지보수성 | 중간 (직접 호출 필요) | 낮음 (서비스 결합도↑) | 높음 (핸들러로 관심사 분리) |
| 적합한 상황 | 빠른 처리, 부수작업 허용 | 로그 등 반드시 남겨야 할 때 | 다양한 후처리 분기 처리, 모듈 분리 |
REQUIRES_NEW@Async@EventListener + @Async