Spring

Spring ๊ธฐ๋ณธ [ ์‹ฑ๊ธ€ํ†ค/์Šคํ”„๋ง์ปจํ…Œ์ด๋„ˆ]

DAHLIA CHOI 2021. 7. 11. 17:09

์›น์˜ ๊ฒฝ์šฐ์—๋Š” ๊ณ ๊ฐ์ด ์—ฌ๋Ÿฌ๋ช…์ด๊ธฐ ๋•Œ๋ฌธ์— ์š”์ฒญํ• ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์ •๋ง์ •๋ง ์‹ฌํ•˜๋‹ค!

 

๊ทธ๋ž˜์„œ ํ•ด๊ฒฐ์„ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.  ๋ฐฉ๋ฒ•์—๋Š” ๋‘๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•œ๋‹ค.

 

1. ์ง์ ‘ ์‹ฑ๊ธ€ํ†ค ์ƒ์„ฑ

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


[ ์ง์ ‘ ์‹ฑ๊ธ€ํ†ค ์ƒ์„ฑ ] 

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

 

  • ์ž‘์„ฑํ•ด์•ผํ•  ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง„๋‹ค.
  • DIP๋ฅผ ์œ„๋ฐ˜ํ•œ๋‹ค. ( ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒดํด๋ž˜์Šค๋ฅผ ์˜์กดํ•œ๋‹ค) 
private static final SingletonService instance = new SingletonService();
  • DIP๋ฅผ ์œ„๋ฐ˜ํ•˜๋ฉด OCP๋„ ์œ„๋ฐ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋งŽ๋‹ค.
  • ๋‚ด๋ถ€์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
  • private ์ƒ์„ฑ์ž๋กœ ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์–ด๋ ต๋‹ค.
    private SingletonService(){} //private๋กœ ์ƒ์„ฑ์ž๋ฅผ ์„ ์–ธํ•ด์„œ ์™ธ๋ถ€์—์„œ new ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋ง‰๋Š”๋‹ค.โ€‹

์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋”์ด์ƒ์˜ ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋ง‰์„ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค!

 

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

 

๊ทธ ์ „๊นŒ์ง€ ์‚ฌ์šฉํ–ˆ๋˜ ์Šคํ”„๋ง์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹ฑ๊ธ€ํ†ค์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉด์„œ๋„ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ 1๊ฐœ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

 

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ์˜ ์—ญํ• ์„ ํ•œ๋‹ค. 
  • ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ผ๊ณ  ํ•œ๋‹ค.
  • ์‹ฑ๊ธ€ํ†ค์„ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ๋”ฐ๋กœ ๋งŽ์ด ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
  • DIP์™€ OCP๋ฅผ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ‘‰ ๋”ฐ๋ผ์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฒ˜์Œ์— ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•œ๋‹ค. 

     ๊ทธ ํ›„ ์ˆ˜๋งŽ์€ ๊ณ ๊ฐ์ด ์š”์ฒญ์„ ํ•œ๋‹ค๊ณ  ํ•ด๋„, ๋งŒ๋“ค์–ด์ง„ 1๊ฐœ์˜ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ์ด ๋œ๋‹ค.

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

 

๐Ÿ‘‰ ์š”์ฒญํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๊ธฐ๋Š” ํ•˜๋‹ค! (@Configuration ์ œ๊ฑฐ)

 

 

๐ŸŸ   ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ• ๋•Œ๋Š” ํ•ญ์ƒ ๋ฌด์ƒํƒœ(stateless)๋ฅผ ์œ ์ง€ํ•ด์•ผํ•œ๋‹ค!!

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

    private int price;

    public int order(String name, int price) {
        System.out.println("name = " + name + " price = " + price);
        this.price = price;
    }
    public int getPrice(){
        return price;
    }
}
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์‚ฌ์šฉ์ž 10000์› ์ฃผ๋ฌธ
        statefulService1.order("userA", 10000);
        //ThreadB : B์‚ฌ์šฉ์ž 20000์› ์ฃผ๋ฌธ
        statefulService2.order("userB", 20000);

        //ThreadA : ์‚ฌ์šฉ์žA ์ฃผ๋ฌธ ๊ธˆ์•ก ํ™•์ธ
        int price = statefulService1.getPrice();
        //ThreadB : ์‚ฌ์šฉ์žA๋Š” 10000์›์„ ๊ธฐ๋Œ€ํ–ˆ์ง€๋งŒ, ๊ธฐ๋Œ€์™€ ๋‹ค๋ฅด๊ฒŒ 20000์› ์ถœ๋ ฅ
        System.out.println("price = " + price);

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

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

์ด ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด A์™€ B์— ๋‹ค๋ฅธ ๊ฐ’์„ ๋„ฃ์—ˆ์ง€๋งŒ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์€ B์˜ ๊ฐ€๊ฒฉ์ธ 2000์›์ด ์ถœ๋ ฅ๋œ๋‹ค.

this.price = price๋ฅผ ์ž‘์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— B์˜ ๊ฐ€๊ฒฉ์ด ๋“ค์–ด์˜ค์ž ๋ณ€๊ฒฝ๋œ ๊ฒƒ์ด๋‹ค.

 

์ด์ฒ˜๋Ÿผ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ๋‚˜์ค‘์— ์›น ์„œ๋น„์Šค์—์„œ ๊ธˆ์ „์ ์ธ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ๋ถ€ํ„ฐ ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

package hello.core.singleton;

public class StatefulService {

    public int order(String name, int price) {
        System.out.println("name = " + name + " price = " + price);
        return price;
    }
}
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์‚ฌ์šฉ์ž 10000์› ์ฃผ๋ฌธ
        int userAPrice = statefulService1.order("userA", 10000);
        //ThreadB : B์‚ฌ์šฉ์ž 20000์› ์ฃผ๋ฌธ
        int userBPrice = statefulService2.order("userB", 20000);
        
        // A์‚ฌ์šฉ์ž ๊ฐ€๊ฒฉ ์ถœ๋ ฅ (10000์› ์ถœ๋ ฅ๋จ)
        System.out.println("price = " + userAPrice);
    }
    static class TestConfig{
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }
}

๋”ฐ๋ผ์„œ ์ด๋ ‡๊ฒŒ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ผญ๊ผญ ์Šคํ”„๋ง ๋นˆ์€ ๋ฌด์ƒํƒœ๋กœ ์„ค๊ณ„ํ•ด์•ผํ•œ๋‹ค.

 

[ @Configuration ]

 

์ „์— ์ž‘์„ฑํ–ˆ๋˜ AppConfig ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด memberService์™€ OrderService๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, memberRepository๊ฐ€ ๋‘๋ฒˆ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ๋‹ค ํ•œ๋ฒˆ ์”ฉ๋งŒ ์ƒ์„ฑ์ด ๋œ๋‹ค.

@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
    @Bean
    public MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }
    @Bean
    public DiscountPolicy discountPolicy(){
        return new RateDiscountPolicy();
    }
    //์—ญํ• ์ด ๋“œ๋Ÿฌ๋‚˜๊ฒŒ ๋ณ€๊ฒฝ
}

 

 

์™œ๊ทธ๋Ÿด๊นŒ?

 

์ด AppConfig์˜ ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•˜๋ฉด class.hello.core.AppConfig๋ผ๊ณ  ์ถœ๋ ฅ ๋  ๊ฒƒ๊ฐ™์€๋ฐ SpringCGLIB๊ฐ€ ๋’ค์— ๋ถ™์€ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ‘‰ AppConfig๊ฐ€ ์•„๋‹Œ AppConfig@SpringCGLIB๊ฐ€ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด ์ค€ ๊ฒƒ์ด๋‹ค.

 

๐Ÿ‘‰ AppConfig@SpringCGLIB๊ฐ€ ๋™์ž‘๋œ ์ด์œ ๋Š” AppConfig ํด๋ž˜์Šค ์œ„์— @Configuration ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์˜€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    @Configuration ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด์ง€ ์•Š์œผ๋ฉด ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœ๋˜๊ณ , ์‹ฑ๊ธ€ํ†ค์ด ๊นจ์ง€๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

    ๊ทธ๋ž˜์„œ @Configuration ์• ๋…ธํ…Œ์ด์…˜์€ ๊ผญ ๋ถ™์—ฌ์•ผํ•œ๋‹ค!!

 

 


์—ฌ๋Ÿฌ ๊ฐ•์˜๋“ค์„ ๋ณด๋ฉด์„œ ๋А๋‚€ ๊ฒƒ์€, ์ค‘๋ณต์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ์ค„์ด๊ณ , ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์„ ํ˜ธํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…์ด๋ฉด์„œ๋„ ๊ฐ€์žฅ ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™๋‹ค...ํด๋ฆฐ์ฝ”๋“œ๋ฅผ ์Šค์Šค๋กœ ์ž˜ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ทธ ๋‚ ๊นŒ์ง€ !!

์ด ๊ธ€์€ ์ธํ”„๋Ÿฐ์˜ ๊น€์˜ํ•œ ๊ฐ•์‚ฌ๋‹˜ ๊ฐ•์˜๋ฅผ ๋ณด๊ณ  ๋ณต์Šต ํฌ์ŠคํŒ…ํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค. ์ •๋ง ์ดˆ๋ณด์ž์—๊ฒŒ ์ถ”์ฒœ๐Ÿ‘๐Ÿ‘