๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ์žฅ์›์ต ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ
๐Ÿ’Š Java & Kotlin & Spring/- spring framework +

[Spring] ApplicationEventPublisher ๋ฅผ ์ด์šฉํ•ด์„œ Event ๋ฅผ ๋ฐœํ–‰ํ•˜๋ฉด ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ ๊นŒ

by Wonit 2022. 8. 15.

ํ•ด๋‹น ๊ธ€์˜ ์ „์ฒด ์†Œ์Šค์ฝ”๋“œ๋Š” 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 ์ด๋‹ค.

 

๋‚ด๊ฐ€ ๊ถ๊ธˆํ•œ ๊ฒƒ์€ ์šฐ์„ 

 

  1. ์™œ Config ์—์„œ ApplicationContext ๋ฅผ Events ์—๊ฒŒ set ํ•˜๋Š”๊ฐ€?
  2. @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 ๋ฅผ ์ „๋‹ฌํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

 

References

๋Œ“๊ธ€