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

 

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

- AppConfig์˜ ๊ฒฝ์šฐ ๋ฉค๋ฒ„ ์„œ๋น„์Šค ๋‹ฌ๋ผ๊ณ ํ•˜๋ฉด ํ•ด๋‹น Impl ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜

- ์š”์ฒญํ• ๋•Œ๋งˆ๋‹ค memberService ์ƒ์„ฑ

 

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

* ์š”์ฒญ์ด ์˜ฌ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด ์ƒ์„ฑ๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธ

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);
    
    //memberService1 != memberService2
    assertThat(memberService1).isNotSameAs(memberService2);
  }
}

 

- ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์—ˆ๋˜ ์Šคํ”„๋ง ์—†๋Š” ์ˆœ์ˆ˜ํ•œ DI ์ปจํ…Œ์ด๋„ˆ์ธ AppConfig๋Š” ์š”์ฒญ์„ ํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ๋‹ค.
- ๊ณ ๊ฐ ํŠธ๋ž˜ํ”ฝ์ด ์ดˆ๋‹น 100์ด ๋‚˜์˜ค๋ฉด ์ดˆ๋‹น 100๊ฐœ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์†Œ๋ฉธ๋œ๋‹ค! -> ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•˜๋‹ค

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

 


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

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

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

- ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ 2๊ฐœ ์ด์ƒ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰์•„์•ผํ•จ

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

 

์‹ฑ๊ธ€ํ†ค ์ƒ์„ฑ

ใ„ด (test)hello.cored.singleton

public class SingletonService {

  //1. static ์˜์—ญ์— ๊ฐ์ฒด๋ฅผ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑํ•ด๋‘”๋‹ค.
  private static final SingletonService instance = new SingletonService();

  //2. public์œผ๋กœ ์—ด์–ด์„œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์ด static ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์กฐํšŒํ•˜๋„๋ก ํ—ˆ์šฉํ•œ๋‹ค.
  public static SingletonService getInstance() {
    return instance;
  }

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

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

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

  ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•ญ์ƒ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜

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

 

ํ…Œ์ŠคํŠธ

@Test
@DisplayName("์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•œ ๊ฐ์ฒด ์‚ฌ์šฉ") 
public void singletonServiceTest() {
  
  //private์œผ๋กœ ์ƒ์„ฑ์ž๋ฅผ ๋ง‰์•„๋‘์—ˆ๋‹ค. ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. //new SingletonService();
  
  //1. ์กฐํšŒ: ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
  SingletonService singletonService1 = SingletonService.getInstance();
  
  //2. ์กฐํšŒ: ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
  SingletonService singletonService2 = SingletonService.getInstance();
  
  //์ฐธ์กฐ๊ฐ’์ด ๊ฐ™์€ ๊ฒƒ์„ ํ™•์ธ
  System.out.println("singletonService1 = " + singletonService1); 
  System.out.println("singletonService2 = " + singletonService2);
  
  // singletonService1 == singletonService2
  assertThat(singletonService1).isSameAs(singletonService2);
  singletonService1.logic();

}

 

* ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์“ฐ๋ฉด ์ž๋™์œผ๋กœ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•จ 

 

* ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๋ฌธ์ œ์ 

- ๊ตฌํ˜„ ์ฝ”๋“œ ๋งŽ์•„์ง

- ์˜์กด๊ด€๊ณ„์ƒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค ์˜์กด (DIP ์œ„๋ฐ˜)

- ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒดํด๋ž˜์Šค ์˜์กดํ•ด์„œ OCP ์œ„๋ฐ˜

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

- ๋‚ด๋ถ€ ์†์„ฑ ๋ณ€๊ฒฝ ๋ฐ ์ดˆ๊ธฐํ™” ์–ด๋ ค์›€

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

-> ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง (์•ˆํ‹ฐํŒจํ„ด์œผ๋กœ ๋ถˆ๋ฆฌ๊ธฐ๋„ ํ•จ)


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

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

 

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

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

  (์Šคํ”„๋ง ๋นˆ ๊ฐ์ฒด ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์„œ ๊ด€๋ฆฌ)

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ ์—ญํ•  (์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ๊ด€๋ฆฌ = ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ)

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ด๋Ÿฐ ๊ธฐ๋Šฅ ๋•๋ถ„์— ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด์˜ ๋ชจ๋“  ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๋ฉด์„œ ๊ฐ์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์œ ์ง€ ๊ฐ€๋Šฅ

  (๊ตฌํ˜„ ์ฝ”๋“œ ๋งŽ์•„์ง€์ง€ ์•Š๊ณ  / DIP, OCP, private ์œผ๋กœ ๋ถ€ํ„ฐ ์ž์œ ๋กญ๊ฒŒ ์‹ฑ๊ธ€ํ†ค ์‚ฌ์šฉ ๊ฐ€๋Šฅ)

 

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

@Test
@DisplayName("์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์‹ฑ๊ธ€ํ†ค")
void springContainer() {
    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);
  }
}

 

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

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


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

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

- ๋ฌด์ƒํƒœ๋กœ ์„ค๊ณ„ (stateless)

> ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋จ

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

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

 

์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์  (์˜ˆ์‹œ)

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;
  } 
}
public class StatefulServiceTest {
  @Test
  void statefulServiceSingleton() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
    StatefulService statefulService1 = ac.getBean("statefulService", StatefulService.class);
    StatefulService statefulService2 = ac.getBean("statefulService", StatefulService.class);

    //ThreadA: A์‚ฌ์šฉ์ž 10000์› ์ฃผ๋ฌธ statefulService1.order("userA", 10000);
    statefulService1.order("userA", 10000);
    //ThreadB: B์‚ฌ์šฉ์ž 20000์› ์ฃผ๋ฌธ statefulService2.order("userB", 20000);
    statefulService1.order("userB", 20000);
    
    //ThreadA: ์‚ฌ์šฉ์žA ์ฃผ๋ฌธ ๊ธˆ์•ก ์กฐํšŒ
    int price = statefulService1.getPrice();
    
    //ThreadA: ์‚ฌ์šฉ์žA๋Š” 10000์›์„ ๊ธฐ๋Œ€ํ–ˆ์ง€๋งŒ, ๊ธฐ๋Œ€์™€ ๋‹ค๋ฅด๊ฒŒ 20000์› ์ถœ๋ ฅ System.out.println("price = " + price);
    Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
  }
  
  static class TestConfig {
    @Bean
    public StatefulService statefulService() {
      return new StatefulService();
    }
  } 
}

 

๋ฌด์ƒํƒœ๋กœ ์„ค๊ณ„!

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

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

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

AppConfig

@Configuration
public class AppConfig {
  @Bean
  public MemberService memberService() {
    return new MemberServiceImpl(memberRepository());
  }
  
  @Bean
  public OrderService orderService() {
    return new OrderServiceImpl(
    memberRepository(),
  } 
  
  @Bean
  public MemberRepository memberRepository() {
    return new MemoryMemberRepository();
  }
  ... 
}

- ๊ฒฐ๊ณผ์ ์œผ๋กœ MemboryMemberRepository๊ฐ€ ๊ฐ๊ฐ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ๋˜๋ฉด์„œ ์‹ฑ๊ธ€ํ†ค์ด ๊นจ์ง€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž„

 

ํ…Œ์ŠคํŠธ

public class MemberServiceImpl implements MemberService {
  private final MemberRepository memberRepository;
  
  //ํ…Œ์ŠคํŠธ ์šฉ๋„
  public MemberRepository getMemberRepository() {
    return memberRepository;
  }
}

public class OrderServiceImpl implements OrderService {
  private final MemberRepository memberRepository;
  
  //ํ…Œ์ŠคํŠธ ์šฉ๋„
  public MemberRepository getMemberRepository() {
    return memberRepository;
  }
}
public class ConfigurationSingletonTest {
  @Test
  void configurationTest() {
    ApplicationContext 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);
    
    //๋ชจ๋‘ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ๊ณ ํ•˜๊ณ  ์žˆ๋‹ค.
    System.out.println("memberService -> memberRepository = " + memberService.getMemberRepository());
    System.out.println("orderService -> memberRepository  = " + orderService.getMemberRepository());
    System.out.println("memberRepository = " + memberRepository);
 
    //๋ชจ๋‘ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ๊ณ ํ•˜๊ณ  ์žˆ๋‹ค.
    assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
    assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
    }
}

- memberRepository ์ธ์Šคํ„ด์Šค๋Š” ๋ชจ๋‘ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ ๋˜์–ด ์‚ฌ์šฉ๋จ

- ๋‘๋ฒˆ ํ˜ธ์ถœ์ด ์•ˆ๋˜๋Š” ๊ฑด๊ฐ€? -> ํ•œ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋จ = ์‹ฑ๊ธ€ํ†ค ๋ณด์žฅํ•ด์ค€๋‹ค๋Š” ๋ง


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

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

@Test
void configurationDeep() {
  ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
  
  //AppConfig๋„ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค.
  AppConfig bean = ac.getBean(AppConfig.class);
  
  System.out.println("bean = " + bean.getClass());
  //์ถœ๋ ฅ: bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
}

- ์ˆœ์ˆ˜ ํด๋ž˜์Šค๋ผ๋ฉด class hello.core.Appconfig๋ผ๊ณ  ์ถœ๋ ฅ๋˜์–ด์•ผํ•˜์ง€๋งŒ

- bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70 ์œผ๋กœ ๋œธ

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


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

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

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

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

- ํฌ๊ฒŒ ๊ณ ๋ฏผํ•  ๊ฒƒ์ด ์—†๋‹ค. ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๋Š” ํ•ญ์ƒ @Configuration ์„ ์‚ฌ์šฉํ•˜์ž.

  • ๋„ค์ด๋ฒ„ ๋ธ”๋Ÿฌ๊ทธ ๊ณต์œ ํ•˜๊ธฐ
  • ๋„ค์ด๋ฒ„ ๋ฐด๋“œ์— ๊ณต์œ ํ•˜๊ธฐ
  • ํŽ˜์ด์Šค๋ถ ๊ณต์œ ํ•˜๊ธฐ
  • ์นด์นด์˜ค์Šคํ† ๋ฆฌ ๊ณต์œ ํ•˜๊ธฐ