본문 바로가기

Spring Boot/비동기 처리

Spring Event : 기본 이벤트 처리 방식

모르면 계속 보자

 

 - Spring Event 기본 동작 원리

 - 이벤트 정의, 퍼블리셔를 통해 이벤트 발행

 - 이벤트 리스너를 구현하고 이벤트 처리

 - 이벤트 클래스, 퍼블리셔, 리스너의 책임과 흐름 명확하게 구분하기

 - 실무에서 이벤트를 활용해 코드 의존도 낮추는 패턴

 


기본 이벤트 처리 방식

Spring Event 시스템은 "발행 - 구독(Publish - Subscribe) 패턴"을 기반으로 한다고 함

즉, 어떤 사건이 발생했을 때 그 사실을 알리는 이벤트를 발행(Publish)하고

해당 이벤트를 구독(Listen)하는 리스너가 이를 처리한다.

밑의 예제들은 Spring Event를 활용해서 회원가입 시 이메일 발송과 같은 동작을 처리하는 예시들이다.

 

1. 이벤트 클래스 정의

이벤트 클래스는 "무슨 일이 일어났는가??"를 표현한다고 함

Spring 4.2 이전에는 ApplicationEvent를 상속해야 했지만, 이후에는 단순한 POJO로도 이벤트를 정의할 수 있다고 함.

public class UserRegisteredEvent {
	private final String email;
    
    // 생성자를 통해 이벤트에 필요한 데이터를 전달함
    public UserRegisteredEvent(String email) {
    	this.email = email;
    }
    
    public String getEmail() {
    	return email;
    }
}

 

이 UserRegisteredEvent는 "회원가입이 발생했다!!" 는 사실을 담는 역할만 한다. 비즈니스 로직은 포함하지 않는다.

 

 

2. 이벤트 퍼블리셔 구현

이벤트 퍼블리셔는 특정 시점에서 이벤트를 발행하는 역할을 한다고 함

가령 회원이 가입되면 UserRegisteredEvent를 퍼블리시한다.

@Service
public class UserService {
	private final ApplicationEventPublisher publisher; // 퍼블리셔
    
    public UserService(ApplicationEventPublisher publisher) {
    	this.publisher = publisher;
    }
    
    public void registerUser(String email) {
    	// 회원가입 로직 이후..
        System.out.println("사용자 등록 완료 : " + email);
        
        // 이벤트 발행(Publish)
        publisher.publishEvent(new UserRegisteredEvent(email));
        System.out.println("이벤트 발행 완료 : " + email);
    }
}

 

이 UserService 내에 있는 ApplicationEventPublisher 타입의 publisher는 이벤트를 Spring 컨테이너로 전달하며,

컨테이너는 등록된 리스너에게 이벤트를 전달한다고 함.

 

 

3. 이벤트 리스너 구현

이벤트 리스너는 발행된 이벤트를 받아서 후속 작업을 수행한다. 비즈니스 로직의 일종이라고 보면 편할 것 같다.

가령 회원가입 완료 시 환영 이메일을 보내는 역할을 맡는다.

@Component
public class UserRegisteredEventListener {
	
    @EventListener
	public void handleUserRegistered(UserRegisteredEvent event) {
    	System.out.println("회원가입 이벤트 수신 : " + event.getEmail());
        System.out.println("환영 이메일 전송 완료");
    }
}

 

 

4. 디렉토리 구조

Spring 프로젝트에서 이벤트 관련 코드와 관련된 디렉토리 구조 예시

src/main/java/com/example/demo/

 - event/

UserRegisteredEvent.java < - 이벤트 클래스

UserRegisteredEventListener.java < - 이벤트 리스너

 - service/

UserService.java < - 이벤트 퍼블리셔

 

이러한 구조를 통해 "이벤트 중심 아키텍처"의 역할이 명확하게 분리된다.

 

 

5. 이벤트 처리 흐름

Spring Event 이벤트 처리 흐름

 

UserService에서 ApplicationEventPublisher 타입의 publishEvent로 이벤트 발행

- > Spring 컨테이너로 전달한다 - > 컨테이너가 Event를 주입받는 등록된 Listener에게 이벤트를 전달한다

- > Listener에서 로직을 통해 처리 완료하고 Service로 돌아옴

 

이 구조를 통해 비즈니스 로직의 의존도를 낮추고, 확장 가능한 이벤트 기반 설계가 가능해짐

 


구성요소 역할 예시 클래스
이벤트(Event) 특정 사건을 표현하는 객체 UserRegisteredEvent
퍼블리셔(Publisher) 이벤트를 발행하는 주체 UserService
리스너(Listener) 이벤트를 처리하는 구독자 UserRegisteredEventListener
컨테이너(Container) 이벤트 전달을 중개 ApplicationEventPublisher

 

발행 - 구독(Publish - Subscribe) 패턴

서비스에서 이벤트를 발행하고, 이벤트를 구독하는 리스너가 이를 처리한다