eventPublisher ์™€ eventListenr ์‚ฌ์šฉ

· โ˜• 3 min read · ๐Ÿ‘€... views

์„œ๋ก 

์ตœ๊ทผ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์„œ๋น„์Šค์˜ ์ ‘์† ์นด์šดํŠธ๋ฅผ ํ‘œ์‹œํ• ๊นŒ ํ•ด๋ดค๋‹ค. (์˜ค๋กœ์ง€ ํฅ๋ฏธ ์œ„์ฃผ๋กœ..)

์ฒ˜์Œ์—๋Š” MeterRegistry ์™€ Counter ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์— ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค.

๊ตฌํ˜„ํ•˜๊ณ  ๋ณด๋‹ˆ ์ •์ž‘ ์ด๊ฑฐ counter ๋ถ€๋ถ„์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜์ง€? ์ค‘์š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ๋Š” ๋ฌด๊ด€ํ•˜๊ฒŒ ์ง„ํ–‰๋˜์•ผ ํ•˜๋Š”๊ฑด๋ฐ ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๋˜ ์ฐจ์— ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด๋ดค๋‹ค.

์ฒ˜์Œ์—๋Š” ์ธํ„ฐ์…‰ํ„ฐ์˜ afterCompletion ์„ ์‚ฌ์šฉํ•ด๋ดค์œผ๋‚˜, lateinit ์„ ์ด์šฉํ•˜๊ณ  ํ•ด๋„ ๊ณ„์† ์ดˆ๊ธฐํ™” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ ์ด๋ฆฌ์ €๋ฆฌ ํ•ด๋ณด๋‹ค๊ฐ€ ๊ฒฐ๊ตญ์€ ์ด๋ ‡๋‹คํ•  ํ•ด๊ฒฐ์ฑ…์„ ๋ชป ์ฐพ๊ณ (์ฝ”ํ‹€๋ฆฐ๊ณผ ์Šคํ”„๋ง์— ๋Œ€ํ•œ ์ง€์‹์ด ๋ถ€์กฑ…), ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ๋‹ค๊ฐ€ EventListener ์„ ํ†ตํ•ด ๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•˜์—ฌ ๋„์ „ํ•ด๋ดค๋‹ค.

1. Events ์ž‘์„ฑ

  • ํ•ด๋‹น ์„œ๋น„์Šค์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Events ํด๋ž˜์Šค

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    object Events {
        private var eventPublisher: ApplicationEventPublisher? = null
        private val log = LoggerFactory.getLogger(this.javaClass)
      
        fun publishEvent(event: Any) {
            when (eventPublisher) {
                null -> {
                    log.warn("no eventPublisher, so don't publish an event.")
                }
                else -> {
                    eventPublisher!!.publishEvent(event)
                }
            }
        }
      
        fun setEventPublisher(eventPublisher: ApplicationEventPublisher) {
            Events.eventPublisher = eventPublisher
        }
    }
    
    • object ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด์คŒ
    • ApplicationEventPublisher ์„ ํ†ตํ•ด ์ด๋ฒคํŠธ๋ฅผ ํผ๋ธ”๋ฆฌ์‹ฑ
    • eventPublisher ์€ null ์ธ ์ƒํƒœ์ด๋ฏ€๋กœ ํผ๋ธ”๋ฆฌ์‹ฑ ํ•˜๊ธฐ ์ „์— setEventPublisher ์„ ํ•ด์ค˜์•ผ ํ•จ

2. EventsInitializer ์ƒ์„ฑ

  • Events ์—์„œ eventPublisher ์„ ์ฃผ์ž…ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด InitializingBean ์„ ์‚ฌ์šฉ

    1
    2
    3
    4
    5
    6
    7
    8
    
    @Configuration
    class EventsInitializer(val context: ApplicationContext) {
      
        @Bean
        fun initEvents(): InitializingBean {
            return InitializingBean { Events.setEventPublisher(context) }
        }
    }
    
    • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Spring Bean Lifecycle ์— ์˜ํ•ด InitializingBean ์ด ์‹คํ–‰์ด ๋˜๊ณ , Events ๊ฐ์ฒด์˜ eventPublisher ์ด ์ฃผ์ž…์ด ๋œ๋‹ค.

3. Events ๋ฅผ ์‚ฌ์šฉํ•  Service ๊ฐ์ฒด

  • Events ๋Š” ํ•„์š”ํ•œ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋˜์ง€๋งŒ, ์ด๋ฒˆ์—๋Š” ์„œ๋น„์Šค ๊ฐ์ฒด์—์„œ ์‚ฌ์šฉ

    1
    2
    3
    4
    5
    6
    7
    8
    
    @Service
    class ListService(private val provider: DataProvider) {
        fun callCachedData(status: String, req: RequestDTO) : PageInfo<DTO>? {
            Events.publishEvent(MakedKey(status, req))
            return provider.get(MakedKey(status, req))
        }
    }
      
    
    • Events.publishEvent() ๋ฅผ ํ†ตํ•ด ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค

4. EventListener ์„ ํ†ตํ•ด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๊ตฌํ˜„

  • ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์„ ์‹œ์ผฐ์œผ๋‹ˆ, ๋ฐœ์ƒ์‹œํ‚จ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›๋Š” ๊ณณ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    @Component
    class EventMetricHandler(private val meterRegistry: MeterRegistry) {
        private val log = LoggerFactory.getLogger(javaClass)
      
        @Async
        @EventListener(value = [MakedKey::class])
        fun handle(evt: MakedKey) {
            val tags =
                    listOf(
                            Tag.of("status", evt.status)
                    )
            val counter = meterRegistry.counter("counter", tags)
            counter.increment()
      
            log.info("increment metric: tag-{}", tags)
        }
    }
    
    • EventListener ์„ ํ†ตํ•ด ๋ฐ›์€ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • status ๋ผ๋Š” tag ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ  ๊ฐ tag ์— ๋Œ€ํ•œ ์นด์šดํŠธ๋ฅผ ์ฆ๊ฐ€์‹œ์ผœ์ค€๋‹ค.
    • ์œ„์˜ ๊ฒฝ์šฐ์—์„œ๋Š” list ๋ผ๋Š” ์กฐํšŒ์— ๋Œ€ํ•ด์„œ ์นด์šดํŠธ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋žœ์žญ์…˜์„ ์‹ ๊ฒฝ์“ธ ํ•„์š”๊ฐ€ ์—†์ง€๋งŒ, ์ €์žฅ ํ˜น์€ ์‚ญ์ œํ–ˆ์„ ๋•Œ์— ๋Œ€ํ•œ ๋ฉ”ํŠธ๋ฆญ์„ ํ•  ๊ฒฝ์šฐ @TransactionalEventListener ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์˜ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์ด์ „ ์ดํ›„ ๋“ฑ์— ๊ด€ํ•œ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ @Async ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

5. @EnableAsync ์ถ”๊ฐ€

  • ์–ด๋–ป๊ฒŒ ๋ณด๋ฉด ๋น„๋™๊ธฐ๋กœ ํ•œ๋‹ค๋Š” ์‹œ์ ์—์„œ ์ฒ˜์Œ ์ถ”๊ฐ€ํ•ด์คฌ์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์€ ์„ค์ •์ด์ง€๋งŒ…

    1
    2
    3
    4
    5
    6
    7
    
    @SpringBootApplication
    @EnableAsync
    class SampleEventApplication
      
    fun main(args: Array<String>) {
        runApplication<SampleEventApplication>(*args)
    }
    
    • @SpringBootApplication ์–ด๋…ธํ…Œ์ด์…˜ ์ž๋ฆฌ์— @EnableAsync๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋œ๋‹ค.

๊ฒฐ๋ก 

  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ๋•Œ Events ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ข‹์€ ๋ฐฉ๋ฒ•์ธ ๊ฒƒ ๊ฐ™๊ณ  ์ข‹์•„๋ณด์ธ๋‹ค. ๋‹ค๋งŒ, ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ข‹์€ ๊ธฐ๋Šฅ์€ ์ •๋ง ๋งŽ์€๋ฐ, ๋ชจ๋ฅด๋Š” ๊ฒƒ๋„ ์ •๋ง ๋งŽ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ทธ๋งŒํผ ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฒƒ๋„ ์ •๋ง ๋งŽ๋‹ค๋Š” ๊ฒƒ์„ ํ•  ๋•Œ๋งˆ๋‹ค ๋Š๋ผ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
Share on

snack
WRITTEN BY
snack
Web Programmer


What's on this Page