개요

Cabi 서비스에서 메일과 슬랙 알림을 연동하기 위해, 스프링에서 사용되는 이벤트에 대해 알아보고, 적용해보고자 한다.


이벤트란?

컴퓨팅에서 이벤트란 프로그램에 의해 감지되고 처리될 수 있는 동작이나 사건을 말한다.

일반적으로 이벤트 기반 시스템은 프로그램에서 처리해야 할 비동기 외부 활동이 있을 때 사용된다.


스프링에서 이벤트를 사용하는 방법

기본적으로 이벤트를 사용하기 위해서, 다음과 같은 구성을 갖는다.

정보를 담는 Event 클래스 - Event를 Publish하는 Publisher - Event를 수신하고, 처리하는 Listener

코드로 구현하면 다음과 같이 작성해볼 수 있다.

Event 클래스

/**
 * 대여 시작 이벤트 클래스
 */
@ToString
@Getter
public class LentStartEvent {
	/**
	 * 메일링 및 알림을 위한 정보들을 가집니다.
	 */
	private final String name;
	private final String email;
	private final Date expiredAt;
	private final Location location;
	private final Integer visibleNum;

	protected LentStartEvent(String name, String email, Date expiredAt, Location location,
			Integer visibleNum) {
		this.name = name;
		this.email = email;
		this.expiredAt = expiredAt;
		this.location = location;
		this.visibleNum = visibleNum;
	}

	/**
	 * 대여 시작 이벤트를 생성합니다.
	 * <p>
	 * 이벤트 생성에서 익셉션을 발생시키면 서비스 로직에 영향을 주므로,
	 * <br>
	 * 이벤트 리스너에서 따로 처리하도록 합니다.
	 *
	 * @param name      대여자 이름
	 * @param email     대여자 이메일
	 * @param expiredAt 대여 만료일
	 * @param location  대여한 캐비넷 위치 정보
	 * @return 이벤트
	 */
	public static LentStartEvent of(String name, String email, Date expiredAt, Location location,
			Integer visibleNum) {
		return new LentStartEvent(name, email, expiredAt, location, visibleNum);
	}
}

값 검증에 대한 예외처리가 필요할 수 있으나, 이벤트 객체를 생성하여 publish하는 곳은 비즈니스 로직이 수행되는 서비스인 경우가 대다수 일 것이므로, 이 경우에 이벤트 생성시에 exception을 발생시키면 비즈니스 로직이 롤백이 되버리는 불상사가 발생할 수 있으므로, listener에서 핸들링을 해줄 때 처리해주는 편이 좋을 것 같다.

원하는 핸들링을 위한 정보들을 받아서 생성하고, publish하면 된다.

이전의 버전에서는 특정 인터페이스들을 상속 받아서 사용하고.. 복잡했었지만 지금은 단순히 이렇게 만들고 설정하면 바로 사용할 수 있다. 스프링 이거 미친거 아니야?

Publisher 사용하기

/**
 * 예시를 위한 서비스입니다. 메일링, 알림 등을 구현하는 서비스라고 가정하고 테스트 용으로 작성했습니다.
 */
@Service
@RequiredArgsConstructor
@Transactional
public class EventTestService {

	// 이벤트를 발행할 수 있도록 ApplicationEventPublisher를 주입받습니다 - 스프링에서 제공하는 기본 빈입니다.
	private final ApplicationEventPublisher publisher;

	// 이벤트를 핸들링하는(메일링, 알람 수행) 가짜 메서드입니다.
	public void sendMail(LentStartEvent event) {
		System.out.println("Service : 아래 정보에 따라 메일을 날리겠다!!\\n" + event);
	}

	// 이벤트를 발행하는(대여 완료) 가짜 메서드입니다. 테스트를 위해 Listen과 Publish가 같이 있지만, 실제 구현 시에는 분리됩니다.
	public void evokeEvent() {
		publisher.publishEvent(
				LentStartEvent.of(
						"까비",
						"[email protected]",
						DateUtil.getNow(),
						Location.of("까비네 집", 2, "방구석"),
						42));
	}
}

간단한 예시를 위해서 부득이하게 TestService에 Listener가 원하는 로직을 위해 호출하는 sendMail이라는 가짜 메서드와, Event를 publish하는 evokeEvent를 작성했다.

스프링에서 기본적으로 제공하는 빈인 ApplicationEventPublisher(인터페이스)를 주입받으면 바로 publish 할 수 있다(스프링 폼 미쳤다).