언어 및 프레임워크/Spring Boot
Spring Boot 고급 시리즈 6편 – 비동기 처리와 이벤트 기반 아키텍처 전략
B컷개발자
2025. 4. 22. 12:21
728x90
Spring Boot에서 @Async와 이벤트 기반 아키텍처를 활용한 비동기 처리 전략을 정리했습니다. 도메인 이벤트 설계와 ApplicationEventPublisher 실전 적용 예제를 소개합니다.
Spring Boot 고급 시리즈 6편 – 비동기 처리와 이벤트 기반 아키텍처 전략
실무에서 이메일 발송, 알림 전송, 로그 저장, 외부 API 호출 등은 사용자의 주 흐름과 분리된 비동기 작업이 필요합니다.
이러한 작업을 처리할 때 Spring Boot에서는 **@Async**와 **ApplicationEventPublisher**를 활용한 이벤트 기반 설계를 통해
코드를 더 유연하고 유지보수 가능하게 만들 수 있습니다.
📌 1. 비동기 처리를 왜 해야 할까?
- 응답 지연 최소화: 클라이언트가 기다릴 필요 없는 작업을 별도로 처리
- 실패 전파 차단: 보조 작업의 실패가 전체 트랜잭션에 영향을 주지 않도록 분리
- 수평 확장 유리: 이벤트 큐나 메시징 시스템으로 발전 가능
✅ 2. Spring의 비동기 처리 – @Async 기본 사용법
1️⃣ 설정: 비동기 활성화
@SpringBootApplication
@EnableAsync
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
2️⃣ 비동기 메서드 선언
@Service
public class EmailService {
@Async
public void sendWelcomeEmail(String email) {
// 이메일 전송 로직
log.info("이메일 전송 시작: {}", email);
try {
Thread.sleep(3000); // 전송 지연 시뮬레이션
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.info("이메일 전송 완료");
}
}
- 호출하는 쪽에서 기다리지 않고, 별도 쓰레드에서 실행됨
- 반환 타입으로 void, Future, CompletableFuture 등 사용 가능
- 주의: 동일 클래스 내부에서 호출 시 비동기 동작 안 함 (프록시 미적용)
🧩 3. 이벤트 기반 아키텍처란?
비즈니스 로직에서 직접 서비스 호출을 하지 않고,
“무슨 일이 발생했다”는 이벤트를 발행하고, 리스너가 이를 처리하는 구조입니다.
✅ 장점
- 결합도 ↓: 발행자와 처리자 간 의존성 제거
- 책임 분리 ↑: 하나의 이벤트에 다수 리스너 대응 가능
- 비동기 전환 용이: 리스너에 @Async 적용만으로 비동기 가능
📦 4. Spring의 ApplicationEvent 기반 이벤트 처리
1️⃣ 도메인 이벤트 정의
public class UserRegisteredEvent {
private final String email;
public UserRegisteredEvent(String email) {
this.email = email;
}
public String getEmail() { return email; }
}
2️⃣ 이벤트 발행
@Service
@RequiredArgsConstructor
public class UserService {
private final ApplicationEventPublisher eventPublisher;
public void registerUser(String email) {
// 회원 가입 로직...
eventPublisher.publishEvent(new UserRegisteredEvent(email));
}
}
3️⃣ 이벤트 리스너 등록
@Component
public class WelcomeEmailEventListener {
@Async
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
// 이메일 발송 처리
log.info("Welcome email sent to: {}", event.getEmail());
}
}
- @EventListener를 사용하면 명시적인 인터페이스 구현 없이 이벤트를 처리할 수 있음
- @Async와 함께 사용하면 비동기 이벤트 처리 가능
🧠 실무 설계 팁
항목 전략
트랜잭션 타이밍 | 이벤트 발행은 트랜잭션 커밋 이후로 지연하는 것이 안전 → @TransactionalEventListener 활용 |
실패 처리 | 이벤트 리스너 내부의 예외는 로깅 후 무시하거나 별도 에러 큐로 분기 처리 |
테스트 전략 | 이벤트 발행 여부 테스트 → @SpyBean 또는 ApplicationListener 사용 |
확장 가능성 | Kafka 등 외부 메시징 시스템으로 이벤트 구조 확장 가능 |
✅ 마무리 요약
항목 정리
@Async | 빠르고 간단한 비동기 처리 |
이벤트 발행 | ApplicationEventPublisher 사용 |
이벤트 처리 | @EventListener, @Async 결합 가능 |
장점 | 결합도 ↓, 확장성 ↑, 유지보수성 ↑ |
확장 방향 | Kafka, RabbitMQ 등 메시지 큐 기반 구조로 전환 용이 |
📌 다음 편 예고
Spring Boot 고급 시리즈 7편: REST API 통합 테스트 전략 – MockMvc부터 RestAssured까지
728x90