언어 및 프레임워크/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