반응형
EventListener
정의
- Event 객체를 spring 에서 제공해주는 publiser Bean의 1개의 Api를 호출할 경우 등록된 Event객체를 사용하는 listener의 비즈니스 로직을 모두 호출 하는 기능
- 비동기 처리 및 결합도가 높은 독립된 비즈니스 로직을 때어낼때 사용합니다
구성
- Bean 객체를 관리하는 ApplicationContext는 ApplicatioinEventPubliser interface를 상속 받습니다
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); // ApplicationEventMulticaster 위임
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
}
getApplicationEventMulticaster()
라는 method를 통해서ApplicationEventMulticaster
를 가져오게 됩니다ApplicationEventMulticaster
를 가져온 후 event 처리를 하게 됩니다
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// code...
initApplicationEventMulticaster();
// code...
}
}
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
}
- ApplicationContext는 refresh(bean 객체를 생성 하고 DI하는)단계에서
initApplicationEventMulticaster()
라는 method를 호출 하게 됩니다 initApplicationEventMulticaster()
내부에서는SimpleApplicationEventMultiCaster
라는 객체를 직접 생성하게 됩니다
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
invokeListener(listener, event);
}
}
}
}
- 최종적으로
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType)
구문에서multicastEvent
method를 호출 하게 됩니다 SimpleApplicationEventMulticaster
는 지금까지 등록된 eventlistener중 event class와 matching listner들을 찾아서 API를 호출해주게 된다
사용 사례
- 복잡한 도메인 사이에 강한 의존성을 제거하기 위해서 사용
- 주문 서비스 개발, 혼합된 비지니스 로직
- 주문 기능
- 결제 기능
- 주문 로직 안에 결제 로직을 넣어야 하는 경우가 발생
- 주문 신청 -> 주문한 내용의 검증(재고 확인) -> 결제 -> 주문 완료
- 현재 Order(주문) 라는 서비스에서 Pay(결제)라는 서비스는 분리되어야 의존성이 낮아 집니다
- Order Service에 Pay Event Listener를 호출하는 형태로 진행하면 결합도를 낮출 수 있습니다
- 주문 서비스 개발, 혼합된 비지니스 로직
- 비동기 처리(메일 전달/slack notification 전달 등)에 사용
- slack과 mail은 언제나 비즈니스 로직에서 때어낼 수 있는 로직이며 비동기로 처리할 수 있습니다
- mail를 위한 서버가 존재할 경우 MQTT를 통해서 전달 할 수 있지만 모놀리식형태일 경우 eventlistener가 좋은 방식 입니다
반응형
'Spring > 개념' 카테고리의 다른 글
SpEL(Spring Expression Language) (0) | 2022.09.07 |
---|---|
Resilience4J (0) | 2022.07.30 |
Spring Transactional 동작 과정 (0) | 2022.04.10 |
AOP (2) | 2022.02.02 |
Logging (0) | 2021.12.17 |