[Spring] ApplicationEventPublisher λ₯Ό μ΄μ©ν΄μ Event λ₯Ό λ°ννλ©΄ μ΄λ€ μΌμ΄ μΌμ΄λ κΉ
ν΄λΉ κΈμ μ 체 μμ€μ½λλ github μμ νμΈν μ μμ΅λλ€. README λ₯Ό μ°Έμ‘°νμΈμ
λͺ©μ°¨
- λκΈ°
- There is No Magic in spring
λκΈ°
μ΅κ·Όμ DDD λ₯Ό νμ΅νλ©΄μ λλ©μΈ μ΄λ²€νΈλΌλ κ²μ μκ² λμλ€.
κ·Έλ¬λ©΄μ Spring μμ ν VM μμμ μ΄λ²€νΈλ₯Ό λ°ννκ³ ν΄λΉ μ΄λ²€νΈλ₯Ό handling νλ μ½λλ₯Ό μ νκ³ , κ·Έμ κ΄λ ¨ν΄μ μ¬λ¬ μ€μ΅μ ν΄λ³΄λ μ€ Spring μμ 무μΈκ° Magic μ΄ μΌμ΄λκ³ μλκ² κ°μ λλμ λ°μλ€.
κΈ΄ λ§ νμ μμ΄ μλμ μ½λλ₯Ό νμΈν΄λ³΄μ.
@Entity(name = "orders")
public class Order {
public static Order create() {
return new Order();
}
@Id
private Long id;
private OrderStatus status = CREATED;
public void cancel() {
OrderCanceled event = OrderCanceled.of(id);
Events.raise(event); // event trigger
status = CANCELED;
}
}
μμ μ½λλ Order λΌλ μ€μ΅μ μν΄ νμν κ°μμ λλ©μΈμ΄λ€.
μ€μ΅μ μλ리μ€μμλ μμ£Ό κ°λ¨ν λ‘μ§λ§μ κ°μ§κ³ μλ€.
μ£Όλ¬Έμ΄ μ·¨μλλ©΄ Membership μ μνλ₯Ό λ³κ²½νλ κ²μ΄ λ€λ€.
ν΄λΉ Order λΌλ κ°μμ λλ©μΈ μ½λμμ μ§μ€ν΄μΌ ν λΆλΆμ cancel()
μ΄λΌλ λ©μλκ° νλ μΌμ΄λ€.
Events λΌλ μ νΈλ¦¬ν°μ± ν΄λμ€μ static λ©μλμΈ raise()
λ₯Ό νΈμΆν΄μ μ΄λ²€νΈλ₯Ό λ°ννλ€.
Events ν΄λμ€λ₯Ό νμΈν΄λ³΄μ
public class Events {
private static ApplicationEventPublisher publisher;
protected static void setPublisher(ApplicationEventPublisher publisher) {
Events.publisher = publisher; // initializing
}
public static void raise(DomainEvent event) {
if (publisher == null) {
throw new IllegalStateException();
}
publisher.publishEvent(event);
}
}
Events ν΄λμ€λ Spring μ EventDispatcher μΈ ApplicationEventPublisher λ₯Ό κ°μΈκ³ μλ μΌμ’ μ Facade μν μ μννλ€.
ν΄λΉ μ½λμμλ raise()
λ₯Ό νΈμΆνκ² λλ€λ©΄ λ©€λ²λ‘ κ°μ§κ³ μλ ApplicationEventPublisher
μ νλ ₯νμ¬ event λ₯Ό publish νλ€.
ApplicationEventPublisher
λ μ€νλ§μμ μ 곡νλ event publisher μΈλ°, Events λΌλ ν΄λμ€μμλ μ¬μ©μ±μ λμ΄κΈ° μν΄μ static μΌλ‘ EventPublisher λ₯Ό μΈλΆμμ μ£Όμ
λ°λλ€.
@Configuration
@RequiredArgsConstructor
public class EventsConfig {
private final ApplicationContext applicationContext;
@Bean
public InitializingBean eventsInitializer() {
return () -> Events.setPublisher(applicationContext);
}
}
Events λ₯Ό μ΄κΈ°ν νκΈ° μν΄μ InitializingBean μ μ¬μ©νλ€.
μ.
μ΄λ° μ λ° κ³Όμ λ€μ ν΄μ£Όκ³ ν΄λΉ μ΄λ²€νΈλ₯Ό λ°κ³ μλ event handler λ‘ κ°λ³΄μ
@Service
@RequiredArgsConstructor
@Slf4j
public class OrderCanceledEventHandler {
private final MembershipTerminateService membershipTerminateService;
@EventListener(OrderCanceled.class)
public void handle(OrderCanceled event) {
log.info("OrderCanceledEvent occurred !! => {}", event);
membershipTerminateService.terminateBy(event.getOrderId());
}
}
@EventListener
μ΄λ
Έν
μ΄μ
μ μΆκ°νλ©΄ ν΄λΉ μ΄λ²€νΈκ° λ°νλ λ Listening νμ¬ νΉμ λ‘μ§μ μνν μ μλλ‘ νλ€.
μ΄λ ν λ§λ²μ΄ μ¨μ΄μλ κ²μΌκΉ?
There is No Magic in spring
λ κ·Έλ λ― There is No Magic in spring μ΄λ€.
λ΄κ° κΆκΈν κ²μ μ°μ
- μ Config μμ
ApplicationContext
λ₯Ό Events μκ² set νλκ°? @EventListener
λ μ΄λ»κ² consuming νλκ°
μΈλ°, νλμ© νμΈν΄λ³΄μ.
μ Config μμ ApplicationContext λ₯Ό Events μκ² set νλκ°?
EventPublisher λ₯Ό λμ μΌλ‘ set ν΄μ£Όλ Config μ½λμμ ApplicationContext
λ₯Ό λ겨μ Events ν΄λμ€μκ² ApplicationEventPublisher
λ₯Ό μ€μ ν΄μ€λ€.
@Configuration
@RequiredArgsConstructor
public class EventsConfig {
private final ApplicationContext applicationContext;
@Bean
public InitializingBean eventsInitializer() {
return () -> Events.setPublisher(applicationContext);
}
}
Events κ° μνλ λ©€λ²λ ApplicationEventPublisher μΈλ° μ ApplicationContext λ₯Ό λκΈΈκΉ?
public class Events {
private static ApplicationEventPublisher publisher;
protected static void setPublisher(ApplicationEventPublisher publisher) {
Events.publisher = publisher;
}
public static void raise(DomainEvent event) {
//...
}
}
μ°λ¦¬κ° μκ³ μλ ApplicationContext
λ IoC Container λ‘μ Bean Factory μν μ μννλ€.
κ·Έλ° ApplicationContext
μλ λ€μν κΈ°λ₯μ΄ μ‘΄μ¬νλλ°, κ·Έμ€ νλκ° λ°λ‘ ApplicationEventPublishing μ΄λ€.
μ€μ μ€νλ§μ μ½λλ₯Ό νμΈνλλΌλ λμΌνλ€
κ·Έλ¦¬κ³ ν΄λΉ ApplicationEventPublisher
μ ꡬνμ ApplicationContext
λ₯Ό μμνκ³ μλ AbstractApplicationContext
μμ μ‘΄μ¬νλ€.
κ²°κ΅ Events
μκ² raise()
λΌλ νλ ₯μ μμ²νκ² λλ©΄ AbstractApplicationContext
μ μ‘΄μ¬νλ publishEvent()
κ° νΈμΆλκ² λλ€.
Event κ° Publish λλ©΄ Spring μμ μ 곡νλ ApplicationEvent
νμ
μΈμ§ λ¨Όμ νμΈνκ³ κ·Έλ μ§ μλ€λ©΄, Custom ν Event λΌλ©΄ ApplicationEvent
μ ꡬνμ²΄μΈ PayloadApplicationEvent
λ‘ λ³ννλ€.
@EventListener
λ μ΄λ»κ² consuming νλκ°
μ΄μ μ¬κΈ°μλΆν° @EventListener
λ μ΄λ»κ² λμνλμ§μ λν μ€λ§λ¦¬κ° λμ¨λ€.
μκΉ λ΄€λ AbstractApplicationContext
μμ μ‘°κΈ λ λ΄λ €κ°λ€ 보면 μ€μ λ‘ Event λ₯Ό multicast νλ κ³³μ΄ λ±μ₯νκ² λλ€.
ApplicationEventMulticaster
λ μ¬λ¬ ApplicationListener κ°μ²΄λ₯Ό κ΄λ¦¬νκ³ μ΄λ²€νΈλ₯Ό publish ν μ μλ λλ‘ νλ μΈν°νμ΄μ€μΈλ°,
μ€μ λ‘ νΈμΆλλ ꡬν체λ λ°λ‘ SimpleApplicationEventMulticaster
μ΄λ€.
κ·Έλ¦¬κ³ ν΄λΉ ꡬν체μ λ΄λΆμμ @EventListener
μ΄λ
Έν
μ΄μ
μ΄ λΆμ ApplicationListener λ€μ λͺ¨λ λΆλ¬μμ μ μ ν Listener μκ² event λ₯Ό μ λ¬νκ² λλ κ²μ΄λ€.