STUDY๐Ÿ„

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

์ด๋ฆฌ์ญ 2025. 4. 15. 18:32

์•ˆ๋…•ํ•˜์„ธ์š”!

์ด๋ฒˆ์—๋Š” ์‹ฑ๊ธ€ํ†ค์— ๊ด€๋ จํ•ด์„œ ๊ณต๋ถ€ํ•˜๊ณ  ์™”์Šต๋‹ˆ๋‹ค!

๊ทธ๋Ÿผ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ณ ๊ณ !!


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

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

๋Œ€๋ถ€๋ถ„์˜ ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ž…๋‹ˆ๋‹ค.

๋ชฐ๋ก  ์›น์ด ์•„๋‹Œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ๋„ ์–ผ๋งˆ๋“ ์ง€ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ณดํ†ต ์—ฌ๋Ÿฌ ๊ณ ๊ฐ์ด ๋™์‹œ์— ์š”์ฒญ์„ ํ•ฉ๋‹ˆ๋‹ค.

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

1. ํด๋ผ์ด์–ธํŠธ A, B, C๊ฐ€ memberService๋ฅผ ์Šคํ”„๋งํ•œํ…Œ ์š”์ฒญ์„ ํ•ฉ๋‹ˆ๋‹ค.

2. ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์—ˆ๋˜ DI ์ปจํ…Œ์ด๋„ˆ(AppConfig)๋Š” new๋กœ memberService๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.

=>A๊ฐ€ ์š”์ฒญํ•˜๋ฉด DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ , B๊ฐ€ ์š”์ฒญํ•˜๋ฉด DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋˜ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ , C๊ฐ€ ์š”์ฒญํ•˜๋ฉด DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋˜ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ ..

3. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด, ๊ณ ๊ฐ์ด 3๋ฒˆ ์š”์ฒญ์„ ํ•˜๋ฉด ๊ฐ์ฒด๊ฐ€ 3๊ฐœ๊ฐ€ ์ƒ์„ฑ์ด ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

๊ทผ๋ฐ, ์ด๊ฑฐ.. ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ๋ƒ๋ฉด์š”..

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๊ณ ๊ฐ์ด ๊ณ„์† ์š”์ฒญ์„ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ, ๊ณ„์† ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ๊ณ„์† ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒŒ ๋ฌธ์ œ์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์ง„์งœ ๊ณ ๊ฐ์—๊ฒŒ ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ์ด๋ ‡๊ฒŒ ๋˜๋‚˜์š”?

์Šคํ”„๋ง์ด ์—†๋Š” ์ˆœ์ˆ˜ํ•œ DI ์ปจํ…Œ์ด๋„ˆ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„ , test ํŒจํ‚ค์ง€์—์„œ hello.core์— singleton์ด๋ž€ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ์•ˆ์— SingletonTest๋ผ๋Š” ์ž๋ฐ” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

public class SingletonTest {

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

        //2. ์กฐํšŒ: ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
        MemberService memberService2 = appConfig.memberService();

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

AppConfig (DI์ปจํ…Œ์ด๋„ˆ)์— memberService๋ฅผ 2๋ฒˆ ์š”์ฒญํ•˜๋ฉด ๊ณผ์—ฐ ๊ฐ์ฒด๊ฐ€ 2๊ฐœ๊ฐ€ ๋‚˜์˜ฌ๊นŒ์š”?

์Šคํ”„๋ง์ด ์—†๋Š” ์ˆœ์ˆ˜ํ•œ DI ์ปจํ…Œ์ด๋„ˆ

๊ฒฐ๊ณผ ์‚ฌ์ง„์„ ๋ณด๋ฉด appConfigํ•œํ…Œ memberService๋ฅผ ๋‹ฌ๋ผ๊ณ  ํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ฒ€์ฆ์„ ํ•œ ๋ฒˆ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

//๊ฒ€์ฆ
//memberService1๊ณผ memberService2๋Š” ๋‹ฌ๋ผ์•ผ ํ•œ๋‹ค.
Assertions.assertThat(memberService1).isNotSameAs(memberService2);

์ž˜ ๋˜๋„ค์š”.

์ด๋Ÿฐ ์‹์œผ๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๊ฐ€ ๊ณ„์† ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์€ ํšจ์œจ์ ์ด์ง€ ๋ชปํ•˜๊ฒ ์ฃ ..?

 

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์—ˆ๋˜ ์Šคํ”„๋ง ์—†๋Š” ์ˆœ์ˆ˜ํ•œ DI ์ปจํ…Œ์ด๋„ˆ์ธ AppConfig๋Š” ์š”์ฒญ์„ ํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ณ ๊ฐ ํŠธ๋ž˜ํ”ฝ์ด ์ดˆ๋‹น 100์ด ๋‚˜์˜ค๋ฉด ์ดˆ๋‹น 100๊ฐœ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์†Œ๋ฉธ๋˜๋Š”๋ฐ, ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์€ ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๊ณ  ๊ณต์œ ํ•˜๋„๋ก ์„ค๊ณ„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด!!


2. ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

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

๊ทธ๋ž˜์„œ, ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ 2๊ฐœ ์ด์ƒ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

์ฝ”๋“œ๋กœ ํ•œ ๋ฒˆ ๋ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์•„๊นŒ ๋งŒ๋“ค์—ˆ๋˜ test์˜ hello.core์˜ singleton ํŒจํ‚ค์ง€์— SingletonService ์ž๋ฐ” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public class SingletonService {

    //์ž๊ธฐ ์ž์‹ ์„ ๋‚ด๋ถ€์˜ private๋กœ ํ•˜๋‚˜ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ, static์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    //์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํด๋ž˜์Šค ๋ ˆ๋ฒจ์— ์˜ฌ๋ผ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
    private static final SingletonService instance = new SingletonService();

    //์กฐํšŒ
    public static SingletonService getInstance() {
        return instance;
    }

    //์ด๋ ‡๊ฒŒ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ํ•ด๋„ ๋ฉ”์ธ ํ•จ์ˆ˜์—์„œ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋งŒ๋“ค์–ด๋ฒ„๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    //๊ทธ๋ž˜์„œ, private ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ์„ ๋ง‰์•„๋ฒ„๋ฆฌ๋ ค๊ณ .
    private SingletonService() {
    }

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

<์ž์„ธํ•œ ์„ค๋ช…>

1. static ์˜์—ญ์— ๊ฐ์ฒด instance๋ฅผ ๋ฏธ๋ฆฌ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด์„œ ์˜ฌ๋ ค๋‘ก๋‹ˆ๋‹ค.

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

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

 

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์šฐ์„ , singleton ํŒจํ‚ค์ง€์˜ SingletonTest ํด๋ž˜์Šค์—์„œ ๋ฐ‘์— ๋งˆ์ € ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

new๋กœ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

private access ๋•Œ๋ฌธ์— ์•ˆ ๋œ๋‹ค๊ณ  ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๋ฅผ ๋”ฑ ์ค˜๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ์ œ๋Œ€๋กœ ํ•œ ๋ฒˆ ์ฝ”๋“œ ์ž‘์„ฑ์„ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

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

์•„๊นŒ์ฒ˜๋Ÿผ singletonService1,2 ์ด 2๊ฐœ๋ฅผ ์กฐํšŒํ•ด๋ณผ๊ฑด๋ฐ์š”.

getInstance๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ฒฐ๊ณผ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‚˜์˜ฌ๊นŒ์š”?

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•œ ๊ฐ์ฒด ์‚ฌ์šฉ

์—‡!! ์•„๊นŒ ์‹ฑ๊ธ€ํ†ค ์ ์šฉ ์ „๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ด๋ฒˆ์—” ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ™์€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฐ˜ํ™˜์ด ๋œ๊ฑฐ์ฃ .

๊ทธ๋Ÿผ ๊ฒ€์ฆํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

assertThat(singletonService1).isSameAs(singletonService2);

์œ„์—์„œ๋„ ๋‚˜์™”๋Š”๋ฐ isSameAs์™€ isEqualTo์˜ ์ •ํ™•ํ•œ ์ฐจ์ด์ ์„ ๋น„๊ตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ”ฅisSameAs vs IsEqualTo๐Ÿ”ฅ

<isSameAs>

- ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์ธ์ง€ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. (์ž๋ฐ”์—์„œ ==๋น„๊ต)
- ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
ex) string a = new String("hello");
      string b = new String("hello");
      string c = a;

      assertThat(a).isSameAs(c); //โœ”๏ธํ†ต๊ณผ (๊ฐ™์€ ๊ฐ์ฒด)
      assertThat(a).isSameAs(b); //โŒ์‹คํŒจ (๋‹ค๋ฅธ ๊ฐ์ฒด์ง€๋งŒ ๊ฐ’์€ ๊ฐ™์Œ)

โญ์ฆ‰, ๊ฐ์ฒด ์ฐธ์กฐ ๋น„๊ต(==)์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์ผ ๋•Œ๋งŒ ํ†ต๊ณผํ•ด์š”.โญ

<isEqualTo>
equals() ๋ฉ”์„œ๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
- ๋‘ ๊ฐ์ฒด์˜ ๋‚ด์šฉ(๊ฐ’)์ด ๊ฐ™์€์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
- obj1.equals(obj2)๊ฐ€ true์ด๋ฉด ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค.
ex) string a = new String("hello");
      string b = new String("hello");
    
      assertThat(a).isEqualTo(b); //โœ”๏ธํ†ต๊ณผ (๋‚ด์šฉ์ด ๊ฐ™์Œ)

โญ์ฆ‰, ๊ฐ’ ๋น„๊ต(.equals())์ž…๋‹ˆ๋‹ค. ๋‚ด์šฉ์ด ๊ฐ™์œผ๋ฉด ํ†ต๊ณผํ•ด์š”.โญ

์˜ค๋Š˜ ํ•œ ๊ฒƒ์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด private๋กœ new ํ‚ค์›Œ๋“œ๋ฅผ ๋ง‰์•„๋‘์—ˆ๊ณ , ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ™์€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ !! ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์ž‡์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด๋‘๋Š” ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ณ  ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

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

ํ•˜์ง€๋งŒ, ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆ˜ ๋งŽ์€ ๋ฌธ์ œ์ ๋“ค์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

<์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๋ฌธ์ œ์ ๐Ÿ‘ป>

- ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ๋งŽ์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.
- ์˜์กด ๊ด€๊ณ„ ์ƒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. -> DIP ์œ„๋ฐ˜!!
- ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•ด์„œ OCP ์›์น™์„ ์œ„๋ฐ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.
- ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
- ๋‚ด๋ถ€ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
- private ์ƒ์„ฑ์ž๋กœ ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
- ๊ฒฐ๋ก ์ ์œผ๋กœ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.
- ์•ˆํ‹ฐ ํŒจํ„ด์œผ๋กœ ๋ถˆ๋ฆฌ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ, ์‹ฑ๊ธ€ํ†ค์„ ๊ณต๋ถ€ํ–ˆ์œผ๋ฏ€๋กœ AppConfig๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ซ™ ๋ฐ”๊พธ๊ณ  getInstance๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ํ•ด๋ณด๋ฉด ๋˜๊ฒ ์ฃ ?

์œ„์˜ ๋‹จ์ ์„ ๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, ์‚ฌ์‹ค ๊ทธ๋Ÿด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


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

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๋ฉด์„œ, ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์‹ฑ๊ธ€ํ†ค(1๊ฐœ๋งŒ ์ƒ์„ฑ)์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

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

 

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

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

์œ„์—์„œ ํ–ˆ๋˜ SingletonTest ์ž๋ฐ” ํด๋ž˜์Šค์—์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋งˆ์ € ์งœ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

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

   //2. ์กฐํšŒ: ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
   MemberService memberService2 = ac.getBean("memberService", MemberService.class);

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

   //๊ฒ€์ฆ
   //memberService1๊ณผ memberService2๋Š” ๊ฐ™์•„์•ผ ํ•œ๋‹ค.
   assertThat(memberService1).isSameAs(memberService2);
}

์•„๊นŒ ์œ„์—์„œ ํ–ˆ๋˜ ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ pureContainer์™€ ์ฝ”๋“œ๋ฅผ ๋น„๊ตํ•ด์„œ ๋ณด๋ฉด ํ™•์‹คํžˆ ๋” ์ž˜ ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์‹ฑ๊ธ€ํ†ค

๊ฐ™์€ ๊ฐ์ฒด๋กœ ๊ฐ€์ ธ์˜จ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์•„๊นŒ ๋งจ ์ฒ˜์Œ์˜ ๊ทธ๋ฆผ์—์„œ ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ ์šฉํ•œ ํ›„๋ฅผ ๋ด๋ณผ๊นŒ์š”?

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

1. ํด๋ผ์ด์–ธํŠธ A, B, C๊ฐ€ memberService๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

2. ๊ฐ์ž์—๊ฒŒ ๋™์ผํ•œ memberService๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.

 

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

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

4. ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์˜ ์ฃผ์˜์ 

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

์ฆ‰, ๋ฌด์ƒํƒœ(Stateless)๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐ€๊ธ‰์  ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„๋“œ ๋Œ€์‹ ์— ์ž๋ฐ”์—์„œ ๊ณต์œ ๋˜์ง€ ์•Š๋Š” ์ง€์—ญ๋ณ€์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ThreadLocal ๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์Šคํ”„๋ง ๋นˆ์˜ ํ•„๋“œ์— ๊ณต์œ  ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ์—„์ฒญ ํฐ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์ด์’€์š”!!ใ… ใ… 

 

์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์  ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Test ํŒจํ‚ค์ง€์—์„œ hello.core์˜ singleton ํŒจํ‚ค์ง€์—์„œ StatefulService ์ž๋ฐ” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public class StatefulService {

    //ํ…Œ์ŠคํŠธ ๊ณผ์ •์„ ํ†ตํ•ด 10,000์›->20,000์›์œผ๋กœ ๋ฐ”๋€Œ์–ด๋ฒ„๋ฆผ
    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;
    }
}

์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฐ€๊ฒฉ์ด๋ผ๋Š” ํ•„๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ€๊ฒฉ ํ•„๋“œ๋Š” ๊ณต์œ  ํ•„๋“œ ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ์ฃผ๋ฌธ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ ์—ฌ๊ธฐ์„œ this.price = price;๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์™œ์ธ์ง€๋Š” ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

StatefulService์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค ๊ทธ๋ƒฅ Test ํŒจํ‚ค์ง€์˜ hello.core์˜ singleton ํŒจํ‚ค์ง€์—์„œ ๊ฑ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ด๋„ ๋˜์ง€๋งŒ ์ €ํฌ๋Š” ๋‹จ์ถ•ํ‚ค๋ฅผ ํ•œ ๋ฒˆ ์จ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Window ๊ธฐ์ค€ ctrl + shift + t๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋ฐ‘์— ์‚ฌ์ง„์ฒ˜๋Ÿผ ๋‚˜์˜ต๋‹ˆ๋‹ค. (Mac์€ command + shift + t)

์‰ฝ๊ฒŒ Test ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

์—ฌ๊ธฐ์„œ ์•„๋ฌด ๊ฒƒ๋„ ๊ฑด๋“ค์ง€ ์•Š๊ณ  ํ™•์ธ์„ ๋ˆ„๋ฆ…๋‹ˆ๋‹ค.

class StatefulServiceTest {

    @Test
    void statefulServiceSingleton() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);
        
        //ThreadA: A ์‚ฌ์šฉ์ž๊ฐ€ 10,000์› ์ฃผ๋ฌธ
        statefulService1.order("userA", 10000);

        //ThreadB: B ์‚ฌ์šฉ์ž๊ฐ€ 20,000์› ์ฃผ๋ฌธ
        statefulService2.order("userB", 20000);

        //ThreadA: A ์‚ฌ์šฉ์ž ์ฃผ๋ฌธ ๊ธˆ์•ก ์กฐํšŒ
        int price = statefulService1.getPrice();

        //ThreadA: A ์‚ฌ์šฉ์ž๋Š” 10,000์›์„ ๊ธฐ๋Œ€ํ–ˆ์ง€๋งŒ ๊ธฐ๋Œ€์™€ ๋‹ค๋ฅด๊ฒŒ 20,000์› ์ถœ๋ ฅ
        System.out.println("price = " + price);
    }

    static class TestConfig {

        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }
}

A ์‚ฌ์šฉ์ž๊ฐ€ 10,000์› ์ฃผ๋ฌธ์„ ํ˜ธ์ถœํ•˜๊ณ , ๋ณธ์ธ์ด ์ฃผ๋ฌธํ•œ ๊ธˆ์•ก์„ ์กฐํšŒํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ๊ทธ ์‚ฌ์ด์— B ์‚ฌ์šฉ์ž๊ฐ€ 20,000์› ์ฃผ๋ฌธ์„ ํ•ด๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

A ์‚ฌ์šฉ์ž๊ฐ€ ์ฃผ๋ฌธํ•œ ๊ธˆ์•ก์„ ์กฐํšŒํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์–ผ๋งˆ๊ฐ€ ๋‚˜์˜ฌ๊นŒ์š”?

Stateful ์˜ˆ์‹œ

์˜ˆ์ƒํ–ˆ๊ฒ ์ง€๋งŒ 20,000์›์ด ๋‚˜์˜ต๋‹ˆ๋‹ค.

statefulService1์ด๋“  statefulService2๋“  ๋“ค์–ด๊ฐ€๋ฉด ์ธ์Šคํ„ด์Šค๋Š” ๊ฐ™์€ ์• ๋กœ ์ธ์‹์„ ํ•ด ๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๊ฐ„์— 20,000์›์œผ๋กœ ๊ธˆ์•ก์ด ๋ฐ”๋€Œ๋ฉด ์กฐํšŒ๋Š” 20,000์›์œผ๋กœ ๋ฉ๋‹ˆ๋‹ค.

 

๊ฒ€์ฆ์„ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

assertThat(statefulService1.getPrice()).isEqualTo(20000);

statefulService1์€ ๋ถ„๋ช… 10,000์›์ด์—ˆ๋Š”๋ฐ ์—ฌ๊ธฐ์„œ 20,000์›๊ณผ ๊ฐ™๋‹ค๊ณ  ๋‚˜์˜ค๋ฉด ์ด ํ…Œ์ŠคํŠธ๋Š” ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์„ ์ž˜๋ชป ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

ํ•œ ๋ฒˆ ํ•ด๋ณผ๊ฒŒ์š”.

Stateful ์˜ˆ์‹œ

๋„ค ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์„œ๋น„์Šค ์ถœ์‹œ๋˜๋ฉด ์•ˆ ๋ผ์š”!

 

- ์ตœ๋Œ€ํ•œ ๋‹จ์ˆœํ•˜๊ฒŒ ๋ณด๊ธฐ ์œ„ํ•ด, ์‹ค์ œ ์“ฐ๋ ˆ๋“œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. (๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ๋„˜๋ฌด ์–ด๋ ค์›Œใ…œใ……ใ…œ)

- ThreadA๊ฐ€ A ์‚ฌ์šฉ์ž ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ThreadB๊ฐ€ B ์‚ฌ์šฉ์ž ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
=> StatefulService์˜ price ํ•„๋“œ๋Š” ๊ณต์œ ๋˜๋Š” ํ•„๋“œ์ธ๋ฐ, ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
=> A ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ๊ธˆ์•ก์€ 10,000์›์ด ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, 20,000์›์ด๋ผ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”์Šต๋‹ˆ๋‹ค.

=> ์‹ค๋ฌด์—์„œ ์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ์ข…์ข… ๋ณด๋Š”๋ฐ, ์ด๋กœ ์ธํ•ด ์ •๋ง ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด ํฐ ๋ฌธ์ œ๋“ค์ด ํ„ฐ์ง‘๋‹ˆ๋‹ค. (๋ช‡ ๋…„์— ํ•œ ๋ฒˆ์”ฉ ๊ผญ ๋งŒ๋‚ฉ๋‹ˆ๋‹ค.)
=> ์ง„์งœ ๊ณต์œ  ํ•„๋“œ๋Š” ์กฐ์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์Šคํ”„๋ง ๋นˆ์€ ํ•ญ์ƒ ๋ฌด์ƒํƒœ(Stateless)๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!!

 

์œ„์˜ ์ƒํƒœ์œ ์ง€(Stateful) ์ฝ”๋“œ๋ฅผ ๋ฌด์ƒํƒœ(Stateless) ์ฝ”๋“œ๋กœ ๋ณ€๊ฒฝํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋กœ ํด๋ž˜์Šค๋Š” ๋งŒ๋“ค์ง€ ์•Š๊ณ , ์œ„ ํด๋ž˜์Šค์—์„œ ์ž‘์—…ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

StatefulService ์ž๋ฐ” ํด๋ž˜์Šค๋กœ ์ด๋™ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public class StatefulService {

    //private int price; //์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฐ€๊ฒฉ์ด๋ผ๋Š” ํ•„๋“œ (Stateful ๋•Œ ์‚ฌ์šฉ)

    //Stateful ๋•Œ ์‚ฌ์šฉ
    /*
    public void order(String name, int price) {
        System.out.println("name = " + name + " price = " + price);
        this.price = price; //์—ฌ๊ธฐ๊ฐ€ ๋ฌธ์ œ!!
    }
    */

    //๊ณต์œ  ํ•„๋“œ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๊ณ , ํ•จ์ˆ˜๋ฅผ void๊ฐ€ ์•„๋‹Œ int๋กœ ํ•ด์„œ return price๋ฅผ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    public int order(String name, int price) {
        System.out.println("name = " + name + " price = " + price);
        //this.price = price; //์—ฌ๊ธฐ๊ฐ€ ๋ฌธ์ œ!!, Stateful ๋•Œ ์‚ฌ์šฉ
        return price;
    }

    //Stateful ๋•Œ ์‚ฌ์šฉ
   /* public int getPrice() {
        return price;
    } */
}

๊ณต์œ  ํ•„๋“œ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๊ณ , ํ•จ์ˆ˜๋ฅผ void๊ฐ€ ์•„๋‹Œ int ๋กœ ํ•ด์„œ return price๋ฅผ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

StatefulServiceTest ์ž๋ฐ” ํด๋ž˜์Šค๋กœ ์ด๋™ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

class StatefulServiceTest {

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

        //ThreadA: A ์‚ฌ์šฉ์ž๊ฐ€ 10,000์› ์ฃผ๋ฌธ
        //statefulService1.order("userA", 10000); //Stateful ๋•Œ ์‚ฌ์šฉ
        int userAPrice = statefulService1.order("userA", 10000);

        //ThreadB: B ์‚ฌ์šฉ์ž๊ฐ€ 20,000์› ์ฃผ๋ฌธ
        //statefulService2.order("userB", 20000); //Stateful ๋•Œ ์‚ฌ์šฉ
        int userBPrice = statefulService1.order("userB", 20000);

        //ThreadA: A ์‚ฌ์šฉ์ž ์ฃผ๋ฌธ ๊ธˆ์•ก ์กฐํšŒ
       // int price = statefulService1.getPrice(); //Stateful ๋•Œ ์‚ฌ์šฉ

        //ThreadA: A ์‚ฌ์šฉ์ž๋Š” 10,000์›์„ ๊ธฐ๋Œ€ํ–ˆ์ง€๋งŒ ๊ธฐ๋Œ€์™€ ๋‹ค๋ฅด๊ฒŒ 20,000์› ์ถœ๋ ฅ
        //System.out.println("price = " + price); //Stateful ๋•Œ ์‚ฌ์šฉ
        System.out.println("price = " + userAPrice);

        //assertThat(statefulService1.getPrice()).isEqualTo(20000);
    }

    static class TestConfig {

        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }
}

๋ฌด์ƒํƒœ์˜ ์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ง€์—ญ๋ณ€์ˆ˜ ์‚ฌ์šฉ์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ง€์—ญ๋ณ€์ˆ˜ userAPrice, userBPrice๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

์ด ์ƒํƒœ์—์„œ userAPrice๋ฅผ ์กฐํšŒํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

Stateless ์˜ˆ์‹œ

ํ…Œ์ŠคํŠธ๊ฐ€ ์ž˜ ํ†ต๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ง€์—ญ๋ณ€์ˆ˜๋Š” ๊ณต์œ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

 

์‹ค๋ฌด์—์„œ ์ด๊ฑฐ ์ง„์งœ ํฌ๊ฒŒ ๋ฌธ์ œ๊ฐ€ ๋˜๋ฉด ๋‚˜์˜ ๊ฒฐ์ œ๋‚ด์—ญ, ๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ๋žŒํ•œํ…Œ ๋ณด์ด๊ณ  ํ•˜๋Š”๊ฑฐ์—์š”..ใ„ทใ„ท

๋ณต๊ตฌํ•˜๋Š”๋ฐ ๋ช‡ ๋‹ฌ์€ ๊ฑธ๋ฆฐ๋‹ค๋„ค์š”.


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

@Configuration์€ ์‹ฑ๊ธ€ํ†ค์„ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

AppConfig ์ž๋ฐ” ํด๋ž˜์Šค๋กœ ์ด๋™ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Configuration
//์„ค์ • ์ •๋ณด, ๊ตฌ์„ฑ ์ •๋ณด
public class AppConfig {

    @Bean
    //๊ฐ ๋ฉ”์„œ๋“œ๋งˆ๋‹ค @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();
    }
}

memberService ๋ถ€๋ถ„์„ ๋ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Bean์ด ์žˆ๊ณ  ๊ทธ ๋‹ค์Œ์— memberService๋ฅผ ํ•˜๋ฉด new๋กœ MemberServiceImpl์„ ํ˜ธ์ถœํ•˜๊ณ , memberRepository๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ new MemoryMemberRepository๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ , orderService ๋ถ€๋ถ„์„ ๋ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Bean์ด ์žˆ๊ณ  ๊ทธ ๋‹ค์Œ์— orderService๋ฅผ ํ•˜๋ฉด new๋กœ OrderServiceImpl์„ ํ˜ธ์ถœํ•˜๊ณ , memberRepository์™€ discountPolicy๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๋˜ new MemoryMemberRepository๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์–ด๋ผ? 2๋ฒˆ ํ˜ธ์ถœ์„ ํ–ˆ๋„ค์š”?

์ด๋Ÿฌ๋ฉด ์‹ฑ๊ธ€ํ†ค์ด ๊นจ์ง€๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€์š”?

 

์ง์ ‘ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

MemberServiceImpl์— ์žˆ๋Š” MemberRepository์˜ ๊ฐ’์„ ํ™•์ธํ•ด๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

MemberServiceImpl ์ฝ”๋“œ๋กœ ์ด๋™ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

//ํ…Œ์ŠคํŠธ ์šฉ๋„
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }

ํ…Œ์ŠคํŠธ ์šฉ๋„์ด๋ฏ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค๊นŒ์ง€ ๋งŒ๋“ค์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.

 

OrderServiceImpl ์ฝ”๋“œ๋กœ๋„ ์ด๋™ํ•ด์„œ ์œ„์—์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

//ํ…Œ์ŠคํŠธ ์šฉ๋„
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }

MemberServiceImpl๊ณผ OrderServiceImpl ์ฝ”๋“œ๋ฅผ ๋ด๋ณด๋ฉด ๋‘˜ ๋‹ค private final MemberRepository memberRepository;๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ…Œ์ŠคํŠธ ์ž๋ฐ” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

test ํŒจํ‚ค์ง€์˜ hello.core์˜ singleton ํŒจํ‚ค์ง€์— ConfigurationSingletonTest ์ž๋ฐ” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public class ConfigurationSingletonTest {
    
    @Test
    void configurationTest() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
    }
}

๋ถ„๋ช… ๊ตฌ์ฒด ํด๋ž˜์Šค๋กœ ๊บผ๋‚ด๋ฉด ์•ˆ ์ข‹๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ ์™œ ๊ตฌ์ฒด ํด๋ž˜์Šค๋กœ ๊บผ๋‚ด๋ƒ๋ฉด..

Impl๋กœ ๊บผ๋‚ด์•ผ ์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ getMemberRepository ํ•จ์ˆ˜๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋งˆ์ € ์ž‘์„ฑ์„ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public class ConfigurationSingletonTest {
    
    @Test
    void configurationTest() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);

        MemberRepository memberRepository1 = memberService.getMemberRepository();
        MemberRepository memberRepository2 = orderService.getMemberRepository();
        
        System.out.println("memberService -> memberRepository = " + memberRepository1);
        System.out.println("orderService -> memberRepository = " + memberRepository2);
    }
}

MemberServiceImpl๊ณผ OrderServiceImpl ๋‘˜ ๋‹ค MemberRepository๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ , MemoryMemberRepository๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ๋ถ„์„ ์ง“๊ธฐ ์œ„ํ•ด์„œ memberRepository1, memberRepository2๋กœ ์ด๋ฆ„์„ ์ง€์—ˆ์Šต๋‹ˆ๋‹ค.

๊ณผ์—ฐ memberRepository1๊ณผ memberRepository2๋Š” ๋‹ค๋ฅธ ์• ๊ฐ€ ๋‚˜์˜ฌ๊นŒ์š”?

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์‹ฑ๊ธ€ํ†ค ๊นจ์ง€๋Š”์ง€ ์•ˆ ๊นจ์ง€๋Š”์ง€ ํ™•์ธ (MemberServiceImpl, OrderServiceImpl ํ™•์ธ)

๊ฒฐ๊ณผ๊ฐ€ ๋˜‘๊ฐ™๊ฒŒ ๋‚˜์™”์Šต๋‹ˆ๋‹ค.

 

๊ฒ€์ฆ์„ ํ•˜๊ธฐ ์ „์— ํ•œ ๊ฐ€์ง€ ๊ณผ์ •์„ ๋” ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Impl์„ ํ†ตํ•ด์„œ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์ง„์งœ MemberRepository๋ฅผ ์กฐํšŒํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Bean์œผ๋กœ ๋“ฑ๋ก๋˜์–ด์žˆ๊ณ , new๋กœ MemoryMemberRepository๋ฅผ ๋ฆฌํ„ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ ๊ฒฐ๊ณผ๋Š” ์˜ˆ์ƒ์ด ๊ฐ€๋Š”๋ฐ์š”.

public class ConfigurationSingletonTest {
    
    @Test
    void configurationTest() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
        //์ถ”๊ฐ€ ํ…Œ์ŠคํŠธ
        MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);

        MemberRepository memberRepository1 = memberService.getMemberRepository();
        MemberRepository memberRepository2 = orderService.getMemberRepository();

        System.out.println("memberService -> memberRepository = " + memberRepository1);
        System.out.println("orderService -> memberRepository = " + memberRepository2);
        //์ถ”๊ฐ€ ํ…Œ์ŠคํŠธ
        System.out.println("memberRepository = " + memberRepository);
    }
}

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

memberRepository ๊ทธ ์ž์ฒด๊นŒ์ง€ ํ™•์ธ

์—ญ์‹œ 3๊ฐœ์˜ ์Šคํ”„๋ง ๋นˆ์€ ๋‹ค ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ๋„ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);

๊ฒ€์ฆ๋„ ์ž˜ ๋งž์Šต๋‹ˆ๋‹ค.

 

์œ„์—์„œ ํ•œ ๊ฒƒ๋“ค์„ ํ•œ ๋ฒˆ ์ •๋ฆฌโœ๏ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

- ํ™•์ธํ•ด๋ณด๋ฉด memberRepository ์ธ์Šคํ„ด์Šค๋Š” ๋ชจ๋‘ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ ๋˜์–ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. (๊ฐ™์€ ์• ๊ฐ€ 1๋ฒˆ ์ƒ์„ฑ)

- AppConfig์˜ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋ถ„๋ช…ํžˆ ๊ฐ๊ฐ 2๋ฒˆ new MemoryMemberRepository๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ๋œ ์ผ ์ผ๊นŒ์š”? ํ˜น์‹œ 2๋ฒˆ ํ˜ธ์ถœ์ด ์•ˆ๋˜๋Š” ๊ฒƒ์ผ๊นŒ์š”?

์‹คํ—˜์„ ํ†ตํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

AppConfig ํด๋ž˜์Šค๋กœ ์ด๋™ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        System.out.println("call AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService() {
        System.out.println("call AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        //return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฒฐ๊ณผ๋Š”

call AppConfig.memberService -> call AppConfig.memberRepository -> call AppConfig.memberRepository -> call AppConfig.orderService -> call AppConfig.memberRepository ํ˜ธ์ถœ์ด ๋˜์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ memberRepository๊ฐ€ ์ด 3๋ฒˆ์ด ํ˜ธ์ถœ์ด ๋˜์–ด์•ผ ํ•˜๊ตฌ์š”.

 

๋ช‡ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š”์ง€ ํ•œ ๋ฒˆ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ConfigurationSingletonTest ๋Œ๋ฆฌ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด์ƒํ•ฉ๋‹ˆ๋‹ค. 

๊ฒฐ๊ณผ๊ฐ€ call AppConfig.memberService ํ˜ธ์ถœ ํ›„, call AppConfig.memberRepository ํ˜ธ์ถœ ํ›„, call AppConfig.orderService๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

memberRepository๊ฐ€ 3๋ฒˆ ํ˜ธ์ถœ๋œ ๊ฒƒ์ด ์•„๋‹Œ.. 1๋ฒˆ ํ˜ธ์ถœ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

์Šคํ”„๋ง์ด ์–ด๋–ป๊ฒŒ๋“  ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด์ฃผ๋ ค๊ณ  ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ๋ฐ‘์—์„œ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


6. @Configuration๊ณผ ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘์˜ ๋งˆ๋ฒ•

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ, ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์ด ๋˜๋„๋ก ๋ณด์žฅํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฐ๋ฐ, ์Šคํ”„๋ง์ด ์ž๋ฐ” ์ฝ”๋“œ๊นŒ์ง€ ์–ด๋–ป๊ฒŒ ํ•˜๊ธฐ๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋ถ„๋ช….. ์œ„์—์„œ ํ•œ ์ž๋ฐ” ์ฝ”๋“œ๋Œ€๋กœ๋ฉด memberRepository๊ฐ€ 3๋ฒˆ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ!!

์Šคํ”„๋ง์€ ํด๋ž˜์Šค์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ๋น„๋ฐ€์€ @Configuration์„ ์ ์šฉํ•œ AppConfig์— ์žˆ์Šต๋‹ˆ๋‹ค.

 

์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ ConfigurationSingletonTest ์ž๋ฐ” ํด๋ž˜์Šค๋กœ ๊ฐ€์„œ ๋ฐ‘์— ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@Test
void configurationDeep() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); //์ด ์ž‘์—…์„ ํ†ตํ•ด ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก
    AppConfig bean = ac.getBean(AppConfig.class); //์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ AppConfig ์กฐํšŒ
        
    //์ถœ๋ ฅ
    System.out.println("bean = " + bean.getClass());
}

์‚ฌ์‹ค AnnotationConfigApplicationContext์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธด ๊ฐ’์€ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ, AppConfig๋„ ์Šคํ”„๋ง ๋นˆ์ด ๋ฉ๋‹ˆ๋‹ค.

 

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ AppConfig ์กฐํšŒ

์ถœ๋ ฅ๋œ ๊ฒƒ์„ ๋ณด๋ฉด bean = class hello.core.AppConfig๊นŒ์ง„ ์˜ˆ์ƒํ•œ ๋Œ€๋กœ ๋งž๊ฒŒ ์ถœ๋ ฅ๋˜์—ˆ๋Š”๋ฐ ๊ทธ ๋’ค์— ์ด์ƒํ•œ๊ฒŒ ์žˆ๋„ค์—ฌ?

์ˆœ์ˆ˜ํ•œ ์ž๋ฐ” ํด๋ž˜์Šค๋ผ๋ฉด class hello.core.AppConfig๊นŒ์ง€ ์ถœ๋ ฅ๋˜๋Š”๊ฒŒ ์ •์ƒ์ธ๋ฐ ๋ง์ž…๋‹ˆ๋‹ค..

 

์˜ˆ์ƒ๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ ํด๋ž˜์Šค ๋ช…์— CGLIB ๊ฐ™์€ ๊ฒƒ์ด ๋ถ™์œผ๋ฉด์„œ ์ƒ๋‹นํžˆ ๋ณต์žกํ•ด์ง„ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

 

๋ง๋กœ๋Š” ๋ณต์žกํ•˜๋‹ˆ ๊ทธ๋ฆผ์œผ๋กœ ํ•œ ๋ฒˆ ๋ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ

<๊ทธ๋ฆผ์— ๋Œ€ํ•œ ์„ค๋ช…โœ๏ธ>

1. ์™ผ์ชฝ - ํด๋ž˜์Šค ๊ด€๊ณ„
- AppConfig: ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์›๋ž˜ ์„ค์ • ํด๋ž˜์Šค (@Configuration์ด ๋ถ™์€ ํด๋ž˜์Šค)
- AppConfig@CGLIB: ์Šคํ”„๋ง์ด ๋Ÿฐํƒ€์ž„ ์‹œ์— CGLIB๋ฅผ ์ด์šฉํ•ด ์ƒ์„ฑํ•œ ํ”„๋ก์‹œ ํด๋ž˜์Šค
๐Ÿ‘‰๐Ÿป์ด ํ”„๋ก์‹œ๊ฐ€ ์‹ค์ œ AppConfig๋ฅผ ์ƒ์†ํ•˜๊ณ , ๋‚ด๋ถ€ ์กฐ์ง์„ ๊ฐ€๋กœ์ฑ„์„œ ๋™์ž‘์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

=> ํ™”์‚ดํ‘œ ๋ฐฉํ–ฅ์€ AppConfig@CGLIB๊ฐ€ AppConfig๋ฅผ ์ƒ์†(ํ™•์žฅ)ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

2. ์˜ค๋ฅธ์ชฝ - ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€
- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์›๋ณธ AppConfig ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  ๋Œ€์‹ , ํ”„๋ก์‹œ ๊ฐ์ฒด(AppConfig@CGLIB)๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
- ์ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ๊ฐ€๋กœ์ฑ„์„œ ์‹ฑ๊ธ€ํ†ค ๋นˆ์„ ๋ณด์žฅํ•˜๋Š” ๋“ฑ ๋‹ค์–‘ํ•œ ๋™์ž‘์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

ex) ์œ„์—์„œ๋„ ํ–ˆ๋˜ ์˜ˆ์‹œ์ธ๋ฐ, @Bean ๋ฉ”์„œ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•ด๋„ ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ๋„ ์ด CGLIB ๋•๋ถ„์ž…๋‹ˆ๋‹ค.

์•„๋ฌดํŠผ, ๊ทธ ์ž„์˜์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ๋ฐ”๋กœ ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ๋ฐ‘์—์ฒ˜๋Ÿผ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•ด์„œ ์ž‘์„ฑ๋˜์–ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. (์‹ค์ œ๋กœ๋Š” CGLIB์˜ ๋‚ด๋ถ€ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋งค์šฐ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.)

 

<AppConfig@CGLIB ์˜ˆ์ƒ ์ฝ”๋“œ>

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

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

๋•๋ถ„์— ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. (์ด ์ด์œ ๋กœ MemberRepository๊ฐ€ 3๋ฒˆ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ , 1๋ฒˆ ํ˜ธ์ถœ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

โœ”๏ธ์ฐธ๊ณ !! AppConfig@CGLIB๋Š” AppConfig์˜ ์ž์‹ ํƒ€์ž…์ด๋ฏ€๋กœ, AppConfig ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

6-1. @Configuration ์ ์šฉํ•˜์ง€ ์•Š๊ณ , @Bean๋งŒ ์ ์šฉํ•˜๋ฉด?

@Configuration์„ ๋ถ™์ด๋ฉด ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” CGLIB ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด์„œ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•˜์ง€๋งŒ, ๋งŒ์•ฝ์— @Bean๋งŒ ์ ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

AppConfig ํด๋ž˜์Šค์—์„œ @Configuration์„ ๋นผ๊ณ  ConfigurationSingletonTest ํด๋ž˜์Šค์˜ configurationDeep ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Configuration ์ œ๊ฑฐ ํ›„ configurationDeep ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธํ•œ ๊ฒฐ๊ณผ

์Šคํ”„๋ง ๋นˆ์€ ์ผ๋‹จ ๋‹ค ๋“ฑ๋ก์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, ์œ„์—์„œ ์–˜๊ธฐํ–ˆ๋˜ ๋ฐ๋กœ memberRepository๊ฐ€ 3๋ฒˆ ํ˜ธ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ฑ๊ธ€ํ†ค์ด ๊นจ์ง„ ๊ฒƒ์ด์ฃ .

1๋ฒˆ์€ @Bean์— ์˜ํ•ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๊ณ , 2๋ฒˆ์€ ๊ฐ๊ฐ memberRepository()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ์œ„์—์„œ ๋ณด์˜€๋˜ CGLIB๊ฐ€ ์•ˆ๋ณด์ด๋„ค์š”. ์ˆœ์ˆ˜ํ•œ ์ž๋ฐ” ์ฝ”๋“œ ๊ทธ๋Œ€๋กœ bean = class hello.core.AppConfig๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ™์€์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ ๋ฒˆ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์œ„์—์„œ ํ…Œ์ŠคํŠธ ํ•œ ํด๋ž˜์Šค์—์„œ configurationTest ํ•จ์ˆ˜๋ฅผ ๋Œ๋ ค๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ๋‚˜์˜ฌ๊นŒ์š”?

@Configuration ์ œ๊ฑฐ ํ›„ configurationTest ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ ํ•œ ๊ฒฐ๊ณผ

์œ„์—์„œ๋ž‘ ๋‹ค๋ฅด๊ฒŒ @ ๋’ค์— ๋ถ€๋ถ„์ด ์…‹ ๋‹ค ๋‹ค๋ฅธ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

๊ทธ๋ฆฌ๊ณ , ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ œ๊ฐ€ ์ง์ ‘ new๋กœ ํ•ด์„œ ๋„ฃ์€ ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค.

(๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋’ค์—์„œ ํ• ๊ฑด๋ฐ @Autowired MemberRepository memberRepository;๋ฅผ ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.)

=> ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๋Œ์–ด๋“ค์ด๋Š” ๊ฑฐ์—์šฉ

 

์–ด์ฐŒ๋˜์—ˆ๋“  ํ™•์ธ์ด ๋๋‚ฌ์œผ๋ฉด @Configuration์ด ๋™์ž‘ํ•˜๋„๋ก ๋‹ค์‹œ ๋Œ๋ ค๋†“์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค!!

<์ •๋ฆฌโœ๏ธ>

- @Bean๋งŒ ์‚ฌ์šฉํ•ด๋„ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜์ง€๋งŒ, ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
๐Ÿ‘‰๐ŸปmemberRepository()์ฒ˜๋Ÿผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ํ•„์š”ํ•ด์„œ ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ๋•Œ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
- ์ฆ‰, ํฌ๊ฒŒ ๊ณ ๋ฏผํ•  ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค. ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๋Š” ํ•ญ์ƒ @Configuration์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค!!

 


์˜ค๋Š˜ ๊ณต๋ถ€๋„ ์ด๋ ‡๊ฒŒ ๋์ด ๋‚ฌ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ๊ด€๋ จํ•ด์„œ ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์•ˆ๋‡ฝ!!