ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SpringBoot] ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์•Œ์•„๋ณด๊ณ  ์Šคํ”„๋ง๋ถ€ํŠธ์˜ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž
    SpringBoot 2024. 3. 1. 08:07

    ๐Ÿ“ ๋“ค์–ด๊ฐ€๋ฉฐ

    ๊ต๋‚ด์˜ ์Šคํฌ์ธ  ๊ฒฝ๊ธฐ ์ƒํ™œ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค 'ํ›•์น˜์น˜'์—์„œ๋Š” ์‚ฌ์šฉ์ž๋“ค์ด ์‘์›ํ•˜๋Š” ํŒ€์— ๋Œ€ํ•ด ์‘์› ๋Œ“๊ธ€์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

    1์ฐจ ๋ฆด๋ฆฌ์ฆˆ ์ดํ›„ ์„œ๋น„์Šค์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์•˜์„ ๋‹น์‹œ, ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด์•ผ๋งŒ ์ƒˆ๋กœ์šด ๋Œ“๊ธ€์ด ๋ฐ˜์˜๋˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์ง€์ ์ด ์žˆ์—ˆ๋‹ค.

    ์ด์ „๊นŒ์ง€๋Š” '๋Œ“๊ธ€'์— ๊ฐ€๊น๊ฒŒ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์ •์˜ํ–ˆ์ง€๋งŒ, ํ•ด๋‹น ํ”ผ๋“œ๋ฐฑ๊ณผ ์ด๋ฒคํŠธ ์Šคํ† ๋ฐ์„ ํ†ตํ•ด ๋„๋ฉ”์ธ ์šฉ์–ด๋ฅผ ์ •๋ฆฌํ•œ ๋’ค์—๋Š” ํ•ด๋‹น ๊ธฐ๋Šฅ์ด '์ฑ„ํŒ…'์— ๊ฐ€๊น๋‹ค๊ณ  ์ •์˜๋ฅผ ๋‚ด๋ฆฌ๊ณ  '์‘์›ํ†ก'์ด๋ผ๊ณ  ๋ช…๋ช…ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

    ๋”ฐ๋ผ์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ๋Œ“๊ธ€์ด ๋ฐ˜์˜๋˜๋Š” ๊ฒƒ์œผ๋กœ ๊ธฐํš์ด ๋ฐ”๋€Œ์–ด ์ƒˆ๋กœ ๊ตฌํ˜„์„ ํ•˜๊ฒŒ ๋๋‹ค.

    ๊ทธ ๊ณผ์ • ์ค‘์—์„œ๋„ ์ด๋ฒˆ์—๋Š” ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋ž€ ๋ฌด์—‡์ด๋ฉฐ, ์™œ ์ด ๊ธฐ๋Šฅ์˜ ๊ตฌํ˜„ ๊ณผ์ •์—์„œ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ๊ทธ๋ฆฌ๊ณ  ์Šคํ”„๋ง๋ถ€ํŠธ์˜ ์ด๋ฒคํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜์–ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์ž‘์„ฑํ•ด๋ณด๊ฒ ๋‹ค.

    ๐ŸŽฑ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜ (EDA)

    ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐ„ ์„ค๊ณ„๋ฅผ ์œ„ํ•œ ์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜ ๋ฐ ๋ชจ๋ธ์ด๋‹ค.

    ์ด๋Š” ๋ถ„๋ฆฌ๋œ ์„œ๋น„์Šค๋“ค ๊ฐ„์˜ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์„ค๊ณ„ ๋˜์—ˆ๋‹ค.

    ์ด๋ฒคํŠธ๋ž€?

    ๋ชจ๋“  ์ค‘์š”ํ•œ ๋ฐœ์ƒ ํ˜น์€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ๊ธฐ๋ก์ด๋‹ค.

    ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜์˜ ๊ตฌ์„ฑ ์š”์†Œ

    1. event producers (publishers)

    - ์ด๋ฒคํŠธ๋ฅผ ์ธ์ง€ํ•˜๊ฑฐ๋‚˜ ์ฐพ๋Š”๋‹ค.

    - ์ด๋ฒคํŠธ๋ฅผ ๋ฉ”์‹œ์ง€๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

    - decoupling ํ•˜๊ฒŒ ๊ตฌ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒคํŠธ์˜ consumer ์™€ ์ด๋ฒคํŠธ์˜ ๊ฒฐ๊ณผ๋ฅผ ์•Œ์ง€ ๋ชปํ•œ๋‹ค.

    - ์ด๋ฒคํŠธ์˜ channel ์„ ํ†ตํ•ด์„œ consumer ์—๊ฒŒ ์ „๋‹ฌ๋œ๋‹ค.

     

    2. event consumers (subscribers)

    - ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœํ–‰๋˜๋ฉด ์•Œ๊ฒŒ ๋œ๋‹ค.

    - ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค.

     

    3. event processing platform

    - ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์˜ฌ๋ฐ”๋ฅธ ์‘๋‹ต์„ ์‹คํ–‰ํ•œ๋‹ค.

     

    ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜์˜ ๋ชจ๋ธ

    1. pub/sub model

    - ํŠน์ • ๋ถ€๋ถ„์„ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋ฐœํ–‰๋˜๋ฉด ๊ตฌ๋…์ž๋“ค์€ ์ด๋ฅผ ์•Œ๊ฒŒ ๋˜๊ณ  ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๊ฒŒ ๋˜๋Š” ๋ฐฉ์‹

     

    2. event streaming model

    - ์ด๋ฒคํŠธ๊ฐ€ ๋กœ๊ทธ๋กœ ๊ธฐ๋ก๋œ๋‹ค.

    - event consumer ์€ ๊ตฌ๋…ํ•˜์ง€ ์•Š๋Š”๋‹ค.

    - consumer ๋“ค์€ stream ์˜ ์–ด๋–ค ๋ถ€๋ถ„์ด๋“  ์ฝ์„ ์ˆ˜ ์žˆ๊ณ , ์–ธ์ œ๋“ ์ง€ stream ์— ์กฐ์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

    - apache kafka ์™€ ๊ฐ™์€ streaming platform ์„ ์ด์šฉํ•œ๋‹ค.

    Event ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

    event ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜์—ฌ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ณ ๋ คํ•˜๊ฒŒ ๋˜๋ฉด, ์„œ๋น„์Šค ๊ฐ„์˜ ์˜์กด์„ฑ์ด ๋ถ„๋ฆฌ๋œ๋‹ค.

    ์šฐ๋ฆฌ ์„œ๋น„์Šค๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด ์„ค๋ช…ํ•˜์ž๋ฉด, ์‘์›ํ†ก์„ ๋“ฑ๋กํ•˜๊ณ  ๋‚˜์„œ ์›น์†Œ์ผ“์„ ์ด์šฉํ•ด ํ•ด๋‹น ๊ฒŒ์ž„(๊ฒฝ๊ธฐ) ํŽ˜์ด์ง€์— ๋จธ๋ฌด๋ฅด๊ณ  ์žˆ๋Š” ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ์‘์›ํ†ก์„ ์ „์†กํ•ด์ค˜์•ผ ํ–ˆ๋‹ค.

    ๊ทธ๋Ÿฌ๋‚˜, ์‘์›ํ†ก์„ ๋“ฑ๋กํ•˜๋Š” ๋กœ์ง๊ณผ ์†Œ์ผ“์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋กœ์ง์€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋กœ์ง์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Š” ์„œ๋กœ ์˜์กดํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค.

    ๋”ฐ๋ผ์„œ ์‘์›ํ†ก์ด ๋“ฑ๋ก๋˜๋ฉด, ์ด๋ฅผ ์ด๋ฒคํŠธ๋กœ ๋ฐœํ–‰ํ•˜๊ณ  ์ด๋ฒคํŠธ๋ฅผ ํ•ธ๋“ค๋งํ•˜๋Š” ๋กœ์ง์—์„œ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœํ–‰๋์Œ์„ ์•Œ๊ฒŒ ๋œ ๋’ค ์ด๋ฅผ ์›น์†Œ์ผ“์„ ์ด์šฉํ•ด ํด๋ผ์ด์–ธํŠธ ์ธก์— ์ „์†กํ•ด ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ์‘์›ํ†ก์ด ํ™”๋ฉด์— ์ ์ ˆํžˆ ๋‚˜ํƒ€๋‚˜๋„๋ก ํ–ˆ๋‹ค.

    ์ฆ‰, ์ด๋ฒคํŠธ๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์„œ๋กœ ์ง์ ‘์ ์œผ๋กœ ์—ฐ๊ด€์ด ์—†๋Š” ๋กœ์ง์ด ์„œ๋กœ ์˜์กดํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

     

    ๊ทธ๋ ‡๋‹ค๋ฉด, ์„œ๋กœ ์—ฐ๊ด€์ด ์—†๋Š” ๋กœ์ง์ด ์˜์กดํ•œ๋‹ค๋Š” ๊ฑด ์–ด๋–ค ์ƒํ™ฉ์ผ๊นŒ?

    ์˜ˆ๋ฅผ ๋“ค์–ด์„œ, ์ด์ปค๋จธ์Šค ์„œ๋น„์Šค์—์„œ

    1. ์ฃผ๋ฌธ์„ ํ•˜๋ฉด

    2. ํฌ์ธํŠธ๋ฅผ ์ง€๊ธ‰ํ•˜๊ณ  

    3. ์ถ”์ฒœ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋กœ์ง์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

     

    ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ 3๊ฐ€์ง€์˜ ๋กœ์ง์€ ๋ชจ๋‘ ์„œ๋กœ ์—ฐ๊ด€์ด ์—†์œผ๋ฏ€๋กœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ „ํŒŒํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค๋Š” ๊ฒƒ์ด ๋Š๊ปด์งˆ ๊ฒƒ์ด๋‹ค.

    ๋งŒ์•ฝ ์ด๋ฒคํŠธ๋ฅผ ์ด์šฉํ•ด ์„œ๋กœ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋œ๋‹ค.

    public class OrderService{
    	public void order(OrderRequestDto orderRequestDto){
    		์ฃผ๋ฌธ(orderRequestDto);
    		ํฌ์ธํŠธ_์ง€๊ธ‰(ํฌ์ธํŠธ ์ง€๊ธ‰์— ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ);
    		์ถ”์ฒœ_์ƒํ’ˆ_์•Œ๊ณ ๋ฆฌ์ฆ˜_๋ณ€๊ฒฝ(์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณ€๊ฒฝ์— ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ);
    	}
    }

    ๋งŒ์•ฝ, ํฌ์ธํŠธ ์ง€๊ธ‰์— ํ•„์š”ํ–ˆ๋˜ ์ •๋ณด๊ฐ€ ๋ฐ”๋€๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด OrderService ์ฆ‰ ์ฃผ๋ฌธ์— ๋Œ€ํ•œ ๋กœ์ง๊นŒ์ง€ ๋ณ€๊ฒฝ์ด ์ „ํŒŒ๋œ๋‹ค.

    ์„œ๋กœ ์—ฐ๊ด€์ด ์—†๋Š” ๋กœ์ง๋ผ๋ฆฌ์˜ ์˜์กด์ด ์ƒ๊ธฐ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์— ์ด๋ฒคํŠธ์˜ ๋ฐœํ–‰์ด ํ•„์š”ํ•ด์ง€๋Š” ๊ฒƒ์ด๋‹ค.

     

    ๐ŸŽฑ ์Šคํ”„๋ง๋ถ€ํŠธ์—์„œ์˜ ์ด๋ฒคํŠธ ๋ฐœํ–‰๊ณผ ๊ตฌ๋… ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

    1. Event

    public record ExampleEvent(ExampleDomain exampleDomain) {
    }

    ๊ธฐ์กด์—๋Š” ์ด๋ฒคํŠธ์— ํ•ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ฐ˜๋“œ์‹œ ApplicationEvent ๋ฅผ ์ƒ์†๋ฐ›์•„์•ผ ํ–ˆ๋‹ค.

    ๊ทธ๋Ÿฌ๋‚˜, ๋” ์ด์ƒ์€ ์ƒ์†๋ฐ›์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

     

    2. EventListener

    @Component
    public class ExampleEventListener {
        @EventListener
        public void listen(ExampleEvent event) {
            // .. do sth with event
        }
    }

    Event Listener ์€ @EventListener ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๋ฉด ๋œ๋‹ค.

     

    3. EventPublisher

    @Service
    @RequiredArgsConstructor
    public class ExampleEventPublisher {
    
        private final ApplicationEventPublisher eventPublisher;
    
        public void publish() {
            eventPublisher.publishEvent(new ExampleEvent(new ExampleDomain()));
        }
    }

    EventPublisher ๋Š” ApplicationEventPublisher ์™€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•œ๋‹ค.

    ์ด์— ๋Œ€ํ•œ ์‹ค์ œ ๊ตฌํ˜„์€ ApplicationContext ์—์„œ ์ด๋ฃจ์–ด์ง„๋‹ค.

    ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ publishEvent ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ Event ๋ฅผ ๋ฐœํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

    ๐ŸŽฑ ์ด๋ฒคํŠธ ๋ฐœํ–‰๊ณผ ๊ตฌ๋…์—์„œ์˜ ํŠธ๋žœ์žญ์…˜

    ํŠธ๋žœ์žญ์…˜๊ณผ ํ•ธ๋“ค๋Ÿฌ์˜ ๋™์ž‘ ์‹œ์ ์„ ์ƒ์„ธํ•˜๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    TransactionPhase.BEFORE_COMMIT

    - ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๊ธฐ ์ „์— ์ด๋ฒคํŠธ๋ฅผ ํ•ธ๋“ค๋งํ•œ๋‹ค.

     

    TransactionPhase.AFTER_COMPLETION

    - ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋œ ์ดํ›„์— ์ด๋ฒคํŠธ๋ฅผ ํ•ธ๋“ค๋งํ•œ๋‹ค.

     

    TransactionPhase.AFTER_COMMIT (default)

    - ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋œ ์ดํ›„์— ์ด๋ฒคํŠธ๋ฅผ ํ•ธ๋“ค๋งํ•œ๋‹ค.

     

    TransactionPhase.AFTER_ROLLBACK

    - ๋กค๋ฐฑ๋œ ์ดํ›„์— ํ•ธ๋“ค๋ง์ด ์ด๋ฃจ์–ด์ง„๋‹ค.

     

    ๐ŸŽฑ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ

    ๋งŒ์•ฝ, ์œ„์˜ ๊ณผ์ •์„ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

    ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ 

    @Service
    @RequiredArgsConstructor
    public class ExampleEventPublisher {
    
        private final ApplicationEventPublisher eventPublisher;
    
        @Transactional
        public void register() throws InterruptedException {
            registerNewMember();
            eventPublisher.publishEvent(new ExampleEvent(new ExampleDomain("example")));
            sendEmail();
        }
    
        public void registerNewMember() throws InterruptedException {
            System.out.println("ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ!");
        }
    
        public void sendEmail() throws InterruptedException {
            System.out.println("์ด๋ฉ”์ผ ์ „์†ก ์™„๋ฃŒ!");
        }
    }
    
    @Component
    @RequiredArgsConstructor
    @Slf4j
    public class ExampleEventListener {
    
        private final ExampleEventPublisher publisher;
    
        @EventListener
        public void listen(ExampleEvent event) throws InterruptedException {
            System.out.println("๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ์ง€๊ธ‰ ์™„๋ฃŒ!");
        }
    }

    ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์„ ์˜ˆ์‹œ๋กœ ๋“ค ์ˆ˜ ์žˆ๋‹ค.

    ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๊ฐ€ ํšŒ์›๊ฐ€์ž…์„ ํ•  ๋•Œ

     

    1. ์ƒˆ๋กœ์šด ํšŒ์›์˜ ์ •๋ณด ์ €์žฅ

    2. ๊ฐ€์ž… ์ถ•ํ•˜ ์ด๋ฉ”์ผ ์ „์†ก

    3. ๊ฐ€์ž… ์ถ•ํ•˜ ํฌ์ธํŠธ ๋ถ€์—ฌ ๊ฐ€ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

     

    ๋งŒ์•ฝ ์ด๊ฐ€ ๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค๋ฉด, ๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ์ด ๋ถ€์—ฌ๋  ๋•Œ๊นŒ์ง€ ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง์ด ๋Œ€๊ธฐ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

    ๊ทธ๋Ÿฌ๋‚˜, ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค๋ฉด ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง์ด ๋Œ€๊ธฐ๋ฅผ ํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ง„๋‹ค.

    ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•

    @Component
    public class ExampleEventListener {
        @EventListener
        @Async
        public void listen(ExampleEvent event) {
            // .. do sth with event
        }
    }

    ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š”, ์œ„์ฒ˜๋Ÿผ @Async ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

     

    ๐ŸŽฑ @Async, @EventListener, @TransactionalEventListener

    ์ฒ˜์Œ ์œ„์˜ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์„ ์ ‘ํ–ˆ์„ ๋•Œ ๋„ˆ๋ฌด ํ—ท๊ฐˆ๋ ธ๋‹ค.

    ๊ทธ๋ž˜์„œ ๋‹ค์–‘ํ•œ ์กฐํ•ฉ์„ ๊ณ ๋ คํ•ด์„œ ์˜ˆ์‹œ๋“ค์„ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

     

    1. ๋™๊ธฐ + @EventListener

    @Service
    @RequiredArgsConstructor
    public class ExampleEventPublisher {
    
        private final ApplicationEventPublisher eventPublisher;
    
        @Transactional
        public void register() throws InterruptedException {
            registerNewMember();
            eventPublisher.publishEvent(new ExampleEvent(new ExampleDomain("example")));
            sendEmail();
        }
    
        public void registerNewMember() throws InterruptedException {
            System.out.println("ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ!");
        }
    
        public void sendEmail() throws InterruptedException {
            System.out.println("์ด๋ฉ”์ผ ์ „์†ก ์™„๋ฃŒ!");
        }
    }
    
    @Component
    @RequiredArgsConstructor
    @Slf4j
    public class ExampleEventListener {
    
        private final ExampleEventPublisher publisher;
    
        @EventListener
        public void listen(ExampleEvent event) throws InterruptedException {
            Thread.sleep(10000);
            System.out.println("๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ์ง€๊ธ‰ ์™„๋ฃŒ!");
        }
    }

    - ํŠธ๋žœ์žญ์…˜ : ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜

    - ์“ฐ๋ ˆ๋“œ : ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ

    - ์‹คํ–‰ ์ˆœ์„œ : ํšŒ์›์˜ ์ •๋ณด ์ €์žฅ ๋กœ์ง์ด ์‹คํ–‰๋œ ์ดํ›„์— ๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ๋ถ€์—ฌ ๋กœ์ง์ด ๋„๋Š” ๋™์•ˆ ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง์€ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ๋ถ€์—ฌ ๋กœ์ง์ด ์™„๋ฃŒ๋œ ์ดํ›„์— ์‹คํ–‰๋œ๋‹ค.

     

    2. ๋น„๋™๊ธฐ(@Async) + @EventListener

    @EventListener
    @Async
    public void listen(ExampleEvent event) throws InterruptedException {
        Thread.sleep(10000);
        System.out.println("๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ์ง€๊ธ‰ ์™„๋ฃŒ!");
    }

    listen ๋ฉ”์„œ๋“œ์—์„œ๋งŒ ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. @Async ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๋ฉด ๋œ๋‹ค.

     

    - ํŠธ๋žœ์žญ์…˜ : ๋ถ„๋ฆฌ๋œ ํŠธ๋žœ์žญ์…˜

    - ์“ฐ๋ ˆ๋“œ : ๋ถ„๋ฆฌ๋œ ์“ฐ๋ ˆ๋“œ

    - ์‹คํ–‰ ์ˆœ์„œ ์ƒˆ๋กœ์šด ํšŒ์›์˜ ์ •๋ณด ์ €์žฅ ๋กœ์ง์ด ์‹คํ–‰๋˜๊ณ , ์ด๋ฒคํŠธ ๋ฐœํ–‰ ์ดํ›„์— ๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ๋ถ€์—ฌ ๋กœ์ง์ด ์‹คํ–‰๋œ๋‹ค. ์ด ๋•Œ, register ๋ฉ”์„œ๋“œ๋Š” listen ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  listen ๋ฉ”์„œ๋“œ์™€๋Š” ๋ณ„๊ฐœ๋กœ ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง์ด ๋ฐ”๋กœ ์‹คํ–‰ ๋œ๋‹ค.

    3. ๋™๊ธฐ + @TransactionalEventListener

    @TransactionalEventListener
        public void listen(ExampleEvent event) throws InterruptedException {
            Thread.sleep(10000);
            System.out.println("๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ์ง€๊ธ‰ ์™„๋ฃŒ!");
        }

    - ํŠธ๋žœ์žญ์…˜ : ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜

    - ์“ฐ๋ ˆ๋“œ : ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ

    - ์‹คํ–‰ ์ˆœ์„œ : ์ด๋ฒคํŠธ ๋ฐœํ–‰ ์ชฝ์—์„œ์˜ ์ปค๋ฐ‹์„ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ listen ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

    ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰์ด ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋‘ ๊ฐ™์€ ์“ฐ๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋œ๋‹ค.

    ๋งŒ์•ฝ, ์ปค๋ฐ‹์ด ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค๋ฉด?

     public void register() throws InterruptedException {
            registerNewMember();
            eventPublisher.publishEvent(new ExampleEvent(new ExampleDomain("example")));
            sendEmail();
        }

    ์œ„์™€ ๊ฐ™์ด @Transactional ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ˆ„๋ฝ๋˜์—ˆ๊ณ , ๋ช…์‹œ์ ์œผ๋กœ ์ปค๋ฐ‹๋„ ํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

    ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋Š” ์–ด๋– ํ•œ ์ปค๋ฐ‹๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— listen ๋ฉ”์„œ๋“œ๋Š” ๋ฌดํ•œ์ •์œผ๋กœ ๋Œ€๊ธฐํ•˜๊ฒŒ ๋œ๋‹ค.

    4. ๋น„๋™๊ธฐ + @TransactionalEventListener

    @TransactionalEventListener
        @Async
        public void listen(ExampleEvent event) throws InterruptedException {
            long threadId = Thread.currentThread().getId();
            System.out.println("listen ์“ฐ๋ ˆ๋“œ: " + threadId);
            System.out.println("๊ฐ€์ž… ์ถ•ํ•˜๊ธˆ ์ง€๊ธ‰ ์™„๋ฃŒ!");
        }

    - ํŠธ๋žœ์žญ์…˜ : ๋ณ„๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜

    - ์“ฐ๋ ˆ๋“œ : ๋ณ„๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ

    - ์‹คํ–‰ ์ˆœ์„œ : ์ƒˆ๋กœ์šด ํšŒ์›์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ , ์ปค๋ฐ‹์ด ๋  ๋•Œ๊นŒ์ง€ listen ๋ฉ”์„œ๋“œ๋Š” ๋Œ€๊ธฐํ•˜๋‹ค๊ฐ€ ์ปค๋ฐ‹์ด ๋œ ์ดํ›„์— listen ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

     

     

    ๋‹ค์Œ ๊ธ€์—์„œ ์ด์–ด์ง‘๋‹ˆ๋‹ค..

    https://dev-seunghee.tistory.com/14

     

    [SpringBoot] ๋„๋ฉ”์ธ ์ด๋ฒคํŠธ๋ฅผ ์•Œ์•„๋ณด๊ณ  AbstractAggregateRoot ๋ฅผ ์ด์šฉํ•ด ์ฑ„ํŒ… ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž

    https://dev-seunghee.tistory.com/12 [SpringBoot] ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์•Œ์•„๋ณด๊ณ  ์Šคํ”„๋ง๋ถ€ํŠธ์˜ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž ๐Ÿ“ ๋“ค์–ด๊ฐ€๋ฉฐ ๊ต๋‚ด์˜ ์Šคํฌ์ธ  ๊ฒฝ๊ธฐ ์ƒํ™œ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค 'ํ›•์น˜์น˜'

    dev-seunghee.tistory.com

     

    ์ถœ์ฒ˜

    https://mangkyu.tistory.com/292

     

    [Spring] ์Šคํ”„๋ง์—์„œ ์ด๋ฒคํŠธ์˜ ๋ฐœํ–‰๊ณผ ๊ตฌ๋… ๋ฐฉ๋ฒ•๊ณผ ์ฃผ์˜์‚ฌํ•ญ, ์ด๋ฒคํŠธ ์‚ฌ์šฉ์˜ ์žฅ/๋‹จ์ ๊ณผ ์‚ฌ์šฉ ์˜ˆ์‹œ

    ์ด๋ฒคํŠธ(Event)๋Š” ๋งค์šฐ ์œ ์šฉํ•˜์ง€๋งŒ ์ƒ๋‹นํžˆ ๊ฐ„๊ณผ๋˜๋Š” ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ž‘๋…„์— ์•„๋งˆ์กด CTO๋Š” ์ด๋ฒคํŠธ ๋“œ๋ฆฌ๋ธ ์•„ํ‚คํ…์ฒ˜๋กœ ๊ฐ€์•ผ ํ•œ๋‹ค๊ณ  ๊ธฐ์กฐ ์—ฐ์„ค์„ ํ•˜๊ธฐ๋„ ํ–ˆ๋Š”๋ฐ, ์ด๋ฒˆ์—๋Š” ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ

    mangkyu.tistory.com

     

Designed by Tistory.