Cabi 서비스에서 메일과 슬랙 알림을 연동하기 위해, 스프링에서 사용되는 이벤트에 대해 알아보고, 적용해보고자 한다.
컴퓨팅에서 이벤트란 프로그램에 의해 감지되고 처리될 수 있는 동작이나 사건을 말한다.
일반적으로 이벤트 기반 시스템은 프로그램에서 처리해야 할 비동기 외부 활동이 있을 때 사용된다.
기본적으로 이벤트를 사용하기 위해서, 다음과 같은 구성을 갖는다.
정보를 담는 Event 클래스 - Event를 Publish하는 Publisher - Event를 수신하고, 처리하는 Listener
코드로 구현하면 다음과 같이 작성해볼 수 있다.
/**
* 대여 시작 이벤트 클래스
*/
@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하면 된다.
이전의 버전에서는 특정 인터페이스들을 상속 받아서 사용하고.. 복잡했었지만 지금은 단순히 이렇게 만들고 설정하면 바로 사용할 수 있다. 스프링 이거 미친거 아니야?
/**
* 예시를 위한 서비스입니다. 메일링, 알림 등을 구현하는 서비스라고 가정하고 테스트 용으로 작성했습니다.
*/
@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 할 수 있다(스프링 폼 미쳤다).