[WIL] 부트캠프 7주차 : Spring Application Event 기본 용어와 튜토리얼 코드

2025. 9. 7. 23:36·Essay/WIL

 

Spring Application Event를 사용해보긴 했지만, 용어와 코드가 어떻게 매칭되는지는 늘 헷갈렸다. 
이번 글에서는 이벤트 관련 용어와 Spring을 이용해 내부 이벤트를 사용할 때 참고할 수 있는 예시 코드를 소개하려 한다. 



1. 이벤트 용어

멘토링 시간에 들었던 예시는 이벤트 관련 용어를 이해하는 데 가장 도움이 되었다. 

마라탕집 3000평 가게에 식사하러 갔다.

테이블A에서 "계산해" 달라고 한다
→ 지나가던 알바가 무전기로 "A테이블 계산이요"라고 전달한다. 
→ 계산 서버가 달려와서 "계산해드리겠습니다"
  • 이벤트 프로듀서 (Publisher) = 테이블A
  • 이벤트 = "계산 해줘" → 커맨드가 아니니깐, “계산해줘” 보다는 "여기 식사 다 했어요!" 일 듯.
  • 이벤트 브로커 = 알바 + 무전기
  • 이벤트 컨슈머 (Listener) = 계산 서버  : 이벤트를 구독하고 있다가 해당 이벤트 발생 시 미리 정의된 로직 실행
  • 이벤트 핸들러 = 실제 실행되는 구체적 처리 로직 → "계산 서버"가 계산 처리

 

2. 코드로 보는 이벤트

소개하는 코드는 Spring에서 이벤트를 언제, 어떻게 발행하고 수신 측에서 어떻게 받아 처리하는지 쉽게 이해할 수 있는 좋은 튜토리얼이 될 것이다. 

*// === 이벤트 클래스 ===*
public class OrderCompletedEvent {
    private String orderId;
    private String userId;
    private List<String> items;
    private int amount;
    private LocalDateTime timestamp;
    
    *// 생성자, getter/setter...*
}

*// === 주문 서비스 (이벤트 발행자) ===*
@Service
public class OrderService {
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void createOrder(String userId, List<String> items, int amount) {
        *// 주문 생성 로직*
        String orderId = UUID.randomUUID().toString();
        
        *// 주문 저장...*
        saveOrder(orderId, userId, items, amount);
        
        *// 이벤트 발행 (기존 코드는 수정 불필요!)*
        OrderCompletedEvent event = new OrderCompletedEvent(orderId, userId, items, amount);
        eventPublisher.publishEvent(event);
        
        System.out.println("📝 주문 생성 완료: " + orderId);
    }
}

*// === 기존 서비스들 ===// 결제 서비스*
@Service
public class PaymentService {
    
    @EventListener
    public void handleOrderCompleted(OrderCompletedEvent event) {
        System.out.println("💳 결제 처리 시작: " + event.getOrderId());
        processPayment(event.getAmount());
        sendPaymentConfirmation(event.getUserId());
    }
}

*// 재고 서비스*  
@Service
public class InventoryService {
    
    @EventListener
    public void handleOrderCompleted(OrderCompletedEvent event) {
        System.out.println("📦 재고 차감 처리: " + event.getOrderId());
        updateStock(event.getItems());
        checkLowStock();
    }
}

*// === 새로운 요구사항 1: 포인트 적립 기능 추가 ===*

@Service  *// 새로운 서비스 추가!*
public class PointService {
    
    @EventListener  *// 기존 코드 수정 없이 리스너만 추가!*
    public void handleOrderCompleted(OrderCompletedEvent event) {
        System.out.println("⭐ 포인트 적립 처리: " + event.getOrderId());
        int points = (int)(event.getAmount() * 0.01); *// 1% 적립*
        addPoints(event.getUserId(), points);
        sendPointNotification(event.getUserId());
    }
}

*// === 새로운 요구사항 2: 이메일 알림 추가 ===*

@Service  *// 또 다른 새로운 서비스!*
public class NotificationService {
    
    @EventListener  *// 또다시 기존 코드 수정 없이!*
    public void handleOrderCompleted(OrderCompletedEvent event) {
        System.out.println("📧 이메일 알림 발송: " + event.getOrderId());
        sendOrderConfirmationEmail(event.getUserId(), event);
        sendSMSNotification(event.getUserId());
    }
}

*// === 새로운 요구사항 3: 배송 준비 추가 ===*

@Service  *// 계속해서 새로운 서비스 추가 가능!*
public class ShippingService {
    
    @EventListener
    public void handleOrderCompleted(OrderCompletedEvent event) {
        System.out.println("🚚 배송 준비 시작: " + event.getOrderId());
        createShippingLabel(event);
        scheduleDelivery(event.getOrderId());
    }
}

*// === 컨트롤러 (실행부) ===*

@RestController
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping("/orders")
    public ResponseEntity<String> createOrder(@RequestBody OrderRequest request) {
        orderService.createOrder(
            request.getUserId(), 
            request.getItems(), 
            request.getAmount()
        );
        
        return ResponseEntity.ok("주문이 접수되었습니다.");
    }
}

 

실행 시 로그:

📝 주문 생성 완료: abc-123-def
💳 결제 처리 시작: abc-123-def
📦 재고 차감 처리: abc-123-def
⭐ 포인트 적립 처리: abc-123-def
📧 이메일 알림 발송: abc-123-def
🚚 배송 준비 시작: abc-123-def

 

3. 이벤트 사용 장점

  1. 기존 코드 수정 없음: OrderService, PaymentService, InventoryService는 전혀 건드리지 않음
  2. 새 서비스 추가: 새로운 비즈니스 로직이 필요하다면 서비스 클래스를 하나 추가하고, 메서드에 @EventListener만 붙이면 된다.
    어떤 이벤트를 리슨할지는 발행된 이벤트 객체와 수신 측에서 정의한 이벤트 객체가 동일한 타입으로 매칭되어 결정된다.
  3. Spring이 자동 처리: Spring이 OrderCompletedEvent가 발행되면 모든 @EventListener를 자동으로 호출
  4. 독립적 실행: 각 리스너는 독립적으로 실행되며, 하나가 실패해도 다른 리스너에 영향 없음
  5. 확장 용이: 쿠폰 서비스, 리뷰 요청 서비스 등 무한히 추가 가능

이렇게 Spring Application Event를 사용하면 기존 코드 변경 없이 새로운 기능을 계속 추가할 수 있습니다!

저작자표시 비영리 변경금지 (새창열림)

'Essay > WIL' 카테고리의 다른 글

[WIL] 루퍼스_부트캠프 9주차  (0) 2025.09.14
[WIL] 부트캠프 8주차  (0) 2025.09.07
[WIL] 부트캠프 6주차  (0) 2025.08.24
[WIL] 부트캠프 5주차  (1) 2025.08.18
[WIL] 부트캠프 4주차  (4) 2025.08.10
'Essay/WIL' 카테고리의 다른 글
  • [WIL] 루퍼스_부트캠프 9주차
  • [WIL] 부트캠프 8주차
  • [WIL] 부트캠프 6주차
  • [WIL] 부트캠프 5주차
devstep
devstep
웹 백엔드 개발자
  • devstep
    개발 여정
    devstep
  • 전체
    오늘
    어제
    • 분류 전체보기 (99) N
      • Java (24)
      • Spring Framework (17)
        • Spring (14)
        • JPA (3)
      • Database (9)
        • RDBMS공통 (1)
        • MySQL (6)
        • Redis (1)
        • Oracle (1)
      • Concept (13)
        • 테스트코드 (4)
        • 클린코드 (2)
        • 성능테스트 (4)
        • 설계 (1)
        • 인증 (1)
        • REST API (1)
      • git (2)
      • Intellij (4)
      • Computer Science (3)
        • 네트워크 (1)
        • 자료구조 (1)
        • 보안 (1)
      • Essay (22) N
        • Learning Essay (10)
        • WIL (12) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    JMeter
    nofile
    대칭암호화
    innodb
    부하테스트
    linux
    bean
    성능테스트
    nginx
    부하테스트도구
    테스트코드
    인텔리제이실행에러
    카프카
    자바메모리모델
    seed
    springsecurity
    JVM
    ClusteredIndex
    tdd
    보안
    DDD
    비대칭암호화
    storageEngine
    component
    aggregate
    applicationcontext
    블록암호화
    JavaMemoryModel
    단위테스트
    클린코드
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
devstep
[WIL] 부트캠프 7주차 : Spring Application Event 기본 용어와 튜토리얼 코드
상단으로

티스토리툴바