Notice
Recent Posts
Recent Comments
Today
Total
01-10 22:06
Link
๊ด€๋ฆฌ ๋ฉ”๋‰ด

Partially Committed

[Spring] ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ ๋ณธ๋ฌธ

๐Ÿ’ป Study !/Spring

[Spring] ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ

WonderJay 2023. 1. 12. 23:40
728x90
๋ฐ˜์‘ํ˜•
SMALL

์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ


# ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์‹ฑ๊ธ€ํ†ค

- ์Šคํ”„๋ง์€ ๊ธฐ์—…์šฉ ์˜จ๋ผ์ธ ์„œ๋น„์Šค ๊ธฐ์ˆ ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ํƒ„์ƒํ•จ.

- ๋Œ€๋ถ€๋ถ„์˜ ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋ฉฐ, ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ณดํ†ต ์—ฌ๋Ÿฌ ๊ณ ๊ฐ๋“ค์ด ๋™์‹œ์— ์š”์ฒญ์„ ํ•จ.

@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(
                memberRepository(),
                discountPolicy());
    }
    @Bean
    public DiscountPolicy discountPolicy() {
        //return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}

  ์œ„์™€ ๊ฐ™์ด DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ž‘์„ฑํ•˜์˜€์„ ๋•Œ, 3 ๋ช…์˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ memberService ๋ฅผ ์š”์ฒญํ•˜๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ณด์ž. ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด DI ์ปจํ…Œ์ด๋„ˆ(AppConfig)๋Š” ๊ฐ๊ฐ ๋‹ค๋ฅธ memberService ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ๊ณ„์† ๋ฐœ์ƒํ•˜๋Š”๋ฐ, ์š”์ฒญ์ด ๋ฐœ์ƒํ•  ๋•Œ ๋งˆ๋‹ค ๊ณ„์† ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. (๋ฌธ์ œ์ )

 

package hello.core.singleton;
import hello.core.AppConfig;
import hello.core.member.MemberService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class SingletonTest {
    @Test
    @DisplayName("์Šคํ”„๋ง ์—†๋Š” ์ˆœ์ˆ˜ํ•œ DI ์ปจํ…Œ์ด๋„ˆ")
    void pureContainer(){
        AppConfig appConfig = new AppConfig();
        // 1. ์กฐํšŒ : ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
        MemberService memberService1 = appConfig.memberService();
        MemberService memberService2 = appConfig.memberService();

        // ์ฐธ์กฐ๊ฐ’์ด ๋‹ค๋ฅธ ๊ฒƒ์„ ํ™•์ธํ•ด๋ณด์ž
        System.out.println("memberService1 = " + memberService1);
        System.out.println("memberService2 = " + memberService2);

        Assertions.assertThat(memberService1).isNotSameAs(memberService2);
    }
}

 ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ ์‹œ, ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ๊ฐ์˜ MemberService ๊ฐ์ฒด๋Š” ์ฐธ์กฐ๊ฐ’์ด ๋‹ค๋ฅธ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

memberService1 = hello.core.member.MemberServiceImpl@ba2f4ec
memberService2 = hello.core.member.MemberServiceImpl@1c1bbc4e

์กฐํšŒ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์–ด์•ผ ํ•˜๋ฏ€๋กœ ์ด๊ฒƒ์ด JVM ๋ฉ”๋ชจ๋ฆฌ์— ์Œ“์ด๋Š” ๊ตฌ์กฐ์ด๋‹ค. (๋น„ํšจ์œจ์ ) ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด ๋”์šฑ ์•ˆ์ข‹์€ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ! ๊ณ ๊ฐ ํŠธ๋ž˜ํ”ฝ์ด ์ดˆ๋‹น 100 ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๋ฉด, ์ดˆ๋‹น 100 ๊ฐœ์˜ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์†Œ๋ฉธ๋  ๊ฒƒ์ด๋‹ค.(๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„)

  >>  ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๊ณ , ๊ณต์œ ํ•˜๋„๋ก ์„ค๊ณ„ํ•˜๋ฉด ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ ์ด๋ฅผ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(singleton pattern) ์ด๋ผ๊ณ  ํ•œ๋‹ค.

 

# ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด (Singleton Pattern)

- ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์ด๋ž€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”ฑ ํ•œ ๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.

- ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ 2๊ฐœ ์ด์ƒ ์ƒ์„ฑ๋˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰์•„์•ผ ํ•œ๋‹ค.

  >>  private ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™ธ๋ถ€์—์„œ ์ž„์˜๋กœ new ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰์œผ๋ฉด ๋œ๋‹ค.

  >> ์•„๋ž˜ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

package hello.core.singleton;

public class SingletonService {
    private static final SingletonService instance = new SingletonService();
    // static ์œผ๋กœ ์„ ์–ธํ•จ์œผ๋กœ์จ ํด๋ž˜์Šค level ์— ์กด์žฌํ•˜๋ฏ€๋กœ ๋‹จ ํ•œ ๊ฐœ๋งŒ ์กด์žฌํ•จ.

    // 1. static ์˜์—ญ์— ๊ฐ์ฒด๋ฅผ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑํ•ด๋‘”๋‹ค.
    public static SingletonService getInstance(){
        return instance;
    }
    // 2. public ์œผ๋กœ ์—ด์–ด์„œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์ด static ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์กฐํšŒํ•˜๋„๋ก ํ—ˆ์šฉ.
    private SingletonService(){
    }
    // 3. ์ƒ์„ฑ์ž๋ฅผ private ์œผ๋กœ ์„ ์–ธํ•ด์„œ ์™ธ๋ถ€์—์„œ new ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋ชปํ•˜๊ฒŒ ๋ง‰์Œ.
    public void logic(){
        System.out.println("์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด logic ํ˜ธ์ถœ");
    }
}

-  ์œ„์™€ ๊ฐ™์ด static ์˜์—ญ์— ๊ฐ์ฒด instance ๋ฅผ ๋ฏธ๋ฆฌ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด๋‘์–ด์„œ ์˜ฌ๋ ค๋‘”๋‹ค.

-  ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๋ฉด getInstance() ๋ฉ”์„œ๋“œ๋กœ๋งŒ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋กœ๋ถ€ํ„ฐ ํ•ญ์ƒ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

-  ์˜ค์ง 1 ๊ฐœ์˜ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋งŒ ์กด์žฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ์ƒ์„ฑ์ž๋ฅผ private ์œผ๋กœ ๋ง‰์•„์„œ ํ˜น์‹œ๋ผ๋„ ์™ธ๋ถ€์—์„œ new ํ‚ค์›Œ๋“œ๋กœ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

 

>> ์•„๋ž˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ณด์ž

@Test
    @DisplayName("์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•œ ๊ฐ์ฒด ์‚ฌ์šฉ")
    void singletonServiceTest(){
        SingletonService singletonService1 = SingletonService.getInstance();
        SingletonService singletonService2 = SingletonService.getInstance();

        System.out.println("singletonService1 = " + singletonService1);
        System.out.println("singletonService2 = " + singletonService2);

        Assertions.assertThat(singletonService1).isSameAs(singletonService2);
    }
singletonService1 = hello.core.singleton.SingletonService@2cd76f31
singletonService2 = hello.core.singleton.SingletonService@2cd76f31

Process finished with exit code 0

-  ์œ„์™€ ๊ฐ™์ด Singleton pattern ์„ ์‚ฌ์šฉํ•œ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•˜์—ฌ๋„ ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ๋ฐฉ์ง€๋œ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

-  Spring ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ์ฒด๋ฅผ singleton ์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•ด์ค€๋‹ค!

-  ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•˜๋ฉด ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•ด์„œ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์•„๋ž˜์˜ ๋ฌธ์ œ์ ์ด ์กด์žฌํ•œ๋‹ค.

 

<์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋ฌธ์ œ์ >

-  ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ๋งŽ์ด ๋“ค์–ด๊ฐ„๋‹ค.

-  ์˜์กด๊ด€๊ณ„ ์ƒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด, DIP ๋ฅผ ์œ„๋ฐ˜.

- ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•ด์„œ OCP ์›์น™์„ ์œ„๋ฐ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์ƒ๊ธด๋‹ค.

- ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.

- ๋‚ด๋ถ€ ์†์„ฑ์„ ๋ณ€๊ฒฝ/์ดˆ๊ธฐํ™” ํ•˜๊ธฐ์— ๊นŒ๋‹ค๋กญ๋‹ค.

- private ์ƒ์„ฑ์ž๋กœ ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์–ด๋ ต๋‹ค.

- ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ ธ์„œ, ์•ˆํ‹ฐ ํŒจํ„ด์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๊ธฐ๋„ ํ•œ๋‹ค.

 

>> ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š ์œ„์™€ ๊ฐ™์€ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ „๋ถ€ ํ•ด๊ฒฐํ•˜๋ฉด์„œ๋„ ๊ฐ์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

 

# ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ

- ์Šคํ”„๋ง ๋นˆ์ด ๋ฐ”๋กœ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋นˆ์ด๋‹ค.

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•˜์ง€ ์•Š์•„๋„ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌํ•ด์ค€๋‹ค. ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฐ์ฒด ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์„œ ๊ด€๋ฆฌํ•œ๋‹ค. ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ ์—ญํ• ์„ ํ•˜๋ฉฐ, ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ ๋•๋ถ„์— ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๋ฉฐ, ๊ฐ์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

- ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์œ„ํ•œ ๋ถ€๊ฐ€์ ์ธ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ DIP, OCP, ํ…Œ์ŠคํŠธ, private ์ƒ์„ฑ์ž๋กœ๋ถ€ํ„ฐ ์ž์œ ๋กญ๊ฒŒ ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

>> ์•„๋ž˜์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ณด์ž

    @Test
    @DisplayName("์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์‹ฑ๊ธ€ํ†ค")
    void springContainer() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        // 1. ์กฐํšŒ : ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
        MemberService memberService1 = ac.getBean("memberService", MemberService.class);
        MemberService memberService2 = ac.getBean("memberService", MemberService.class);

        // ์ฐธ์กฐ๊ฐ’์ด ๊ฐ™์€ ๊ฒƒ์„ ํ™•์ธํ•ด๋ณด์ž
        System.out.println("memberService1 = " + memberService1);
        System.out.println("memberService2 = " + memberService2);

        Assertions.assertThat(memberService1).isSameAs(memberService2);
    }

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋•๋ถ„์— ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ๋งˆ๋‹ค, ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•ด์„œ ํ›จ์”ฌ ํšจ์œจ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

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

 

# ๐Ÿง ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์˜ ์ฃผ์˜์ 

- ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•˜๋“  ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋“  ์–ด์ฐŒ๋˜์—ˆ๋“  ๊ฐ„์— ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด ๋ฐ”๋กœ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์ด๋‹ค. ์ด๋Ÿฌํ•œ ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ™์€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€(stateful)ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค. stateless ํ•˜๋„๋ก ์„ค๊ณ„ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด์„œ ์•„๋ž˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.

(1) ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค.

(2) ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค.

(3) ๊ฐ€๊ธ‰์ ์ด๋ฉด ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค.

(4) ํ•„๋“œ ๋Œ€์‹ ์— ์ž๋ฐ”์—์„œ ๊ณต์œ ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ์ง€์—ญ ๋ณ€์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ThreadLocal ๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

 

๐Ÿ˜’์Šคํ”„๋ง ๋นˆ์˜ ํ•„๋“œ์— ๊ณต์œ ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ํฐ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž!

package hello.core.singleton;

public class StatefulService {
    private int price; // ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ํ•„๋“œ
    public void order(String name, int price){
        System.out.println("name = " + name + " price = " + price);
        this.price = price; // <-- ์—ฌ๊ธฐ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ!
    }
    public int getPrice(){
        return price;
    }
}

์œ„์™€ ๊ฐ™์ด StatefulService ํด๋ž˜์Šค๋ฅผ ์„ ์–ธํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

package hello.core.singleton;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;


class StatefulServiceTest {
    @Test
    void statefulServiceTest(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        // ThreadA : A ์‚ฌ์šฉ์ž๊ฐ€ 10000 ์› ์ฃผ๋ฌธ
        statefulService1.order("userA", 10000);
        // ThreadB : B ์‚ฌ์šฉ์ž๊ฐ€ 20000 ์› ์ฃผ๋ฌธ
        statefulService2.order("userB", 20000);
        // ThreadA : ์‚ฌ์šฉ์žA ์ฃผ๋ฌธ ๊ธˆ์•ก ์กฐํšŒ
        int price = statefulService1.getPrice();
        System.out.println("price = " + price);

        Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
    }
    static class TestConfig{
        @Bean
        public StatefulService statefulService(){
            return new StatefulService();
        }
    }

}

์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์ƒํ™ฉ์€ ๋‹จ์ˆœํ•˜๋‹ค. ์‚ฌ์šฉ์ž A ๊ฐ€ 10000 ์›์„ ์ฃผ๋ฌธํ•˜๊ณ  ์ด์–ด์„œ ๋ฐ”๋กœ ์‚ฌ์šฉ์ž B ๊ฐ€ 20000 ์›์„ ์ฃผ๋ฌธํ•˜์˜€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ statefulService1.getPrice() ๋ฅผ ๊บผ๋‚ด์„œ ์‚ฌ์šฉ์ž A ๊ฐ€ ์ฃผ๋ฌธํ•œ ๊ธˆ์•ก์„ ํ™•์ธํ•ด๋ณด๋ฉด 10000 ์›์ด ์•„๋‹ˆ๋ผ 20000 ์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค... ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ฐ˜๋“œ์‹œ ์Šคํ”„๋ง ๋นˆ์€ ๋ฌด์ƒํƒœ(stateless)๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค!

์˜ˆ๋ฅผ ๋“ค์–ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค๊ณ„ํ•˜๋ฉด ๋œ๋‹ค.

public class StatefulService {
    public int order(String name, int price){
        System.out.println("name = " + name + " price = " + price);
        return price;
    }
}

 

 

# @Configuration ๊ณผ ์‹ฑ๊ธ€ํ†ค

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์ด๋ฏ€๋กœ ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์ด ๋˜๋„๋ก ๋ณด์žฅํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์Šคํ”„๋ง์ด ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ์ผ์ผ์ด ์ œ์–ดํ•˜๊ธฐ๋Š” ์–ด๋ ค์šด๋ฐ, ์ด๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ CGLIB ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. AppConfig ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ ์ž„์˜์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“  ๋‹ค์Œ์— ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค. ์ด ์ž„์˜์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด์ฃผ๋„๋ก ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ๋Œ€๋žต ์•„๋ž˜์˜ ์›๋ฆฌ๋กœ ์ž‘์„ฑ๋˜์—ˆ์„ ๊ฒƒ์ด๋‹ค.

@Bean
public MemberRepository memberRepository(){
	if(memoryMemberRepository ๊ฐ€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค๋ฉด){
    		return ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ด๋ฅผ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜;
       }
    else { // ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์—†๋‹ค๋ฉด
    	๊ธฐ์กด ๋กœ์ง์„ ํ˜ธ์ถœํ•˜์—ฌ MemoryMemberRepository ๋ฅผ ์ƒ์„ฑํ•œ ๋‹ค์Œ์— ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก
        return ๋ฐ˜ํ™˜
    }
 }

- @Bean ์ด ๋ถ™์–ด์žˆ๋Š” ๋ฉ”์„œ๋“œ๋งˆ๋‹ค ์ด๋ฏธ ์Šคํ”„๋ง ๋นˆ์ด ์ปจํ…Œ์ด๋„ˆ์— ์กด์žฌํ•˜๋ฉด, ์กด์žฌํ•˜๋Š” ๋นˆ์„ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์Šคํ”„๋ง ๋นˆ์ด ์ปจํ…Œ์ด๋„ˆ์— ์—†๋‹ค๋ฉด ์ƒ์„ฑํ•ด์„œ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋™์ ์œผ๋กœ ๋งŒ๋“ค์–ด ์ง€๋Š” ๊ฒƒ์ด๋ฉฐ ์ด ๋•๋ถ„์— ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

- ์ •๋ฆฌํ•˜์ž๋ฉด @Bean ๋งŒ ์‚ฌ์šฉํ•ด๋„ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜์ง€๋งŒ ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค. ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๋Š” ํ•ญ์ƒ @Configuration ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋งŒ์‚ฌํ•ด๊ฒฐ!


 

Reference

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์Šคํ”„๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ™•์‹คํžˆ ๋‹ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com

 

728x90
๋ฐ˜์‘ํ˜•
LIST
Comments