Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

프로토타입 빈과 싱글톤 빈을 같이 사용하면? 본문

인프런/[인프런] Spring 핵심원리 이해

프로토타입 빈과 싱글톤 빈을 같이 사용하면?

Seung__ 2021. 7. 31. 00:46
  • 프로토타입 빈은 스프링 컨테이너에 요청할 때 마다 새로운 인스턴스 생성하여 반환함.
  • 그런데 싱글톤 빈과 같이 사용하면 의도치 않은 동작을 한다.

 

 

1. 프로토타입 빈 직접 요청


  • 어떤 protoType Bean이 있다고 하자.
  • 해당 클래스에는 addCound method를 제공한다.
  • 만약 A client가 prototypeBean을 요청하고 prototypeBean1이라는 이름으로 받으려고 한다.
  • 스프링 컨테이너는 인스턴스를 새로 생성해서 반환한다(prototypeBean1, @x01)
  • 그리고 client A는 addcount를 실행한다.ㄷ
  • protypeBean.getCount를 하면 1이 리턴된다.
  • 이 때 Client B도 prototypeBean을 요청하고 prototypeBean2라는 이름으로 받으려고 한다.
  • 스프링 컨테이너는 인스턴스를 새로 생성해서 반환한다.(prototypeBean2, @x02)
  • client B는 addcount를 실행한다.
  • prototypeBean2.getCount를 실행하면 1이 리턴될 것이다.
  • public class SingletonWithPrototypeTest1 {
    
        @Test
        public void  prototypeFind(){
    
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
            PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
            prototypeBean1.addCount();
            Assertions.assertThat(prototypeBean1.getCount()).isEqualTo(1);
    
            PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
            prototypeBean2.addCount();
            Assertions.assertThat(prototypeBean2.getCount()).isEqualTo(1);
        }
    
        @Component
        @Scope("prototype")
        static class PrototypeBean{
            private int count = 0;
    
            public void addCount(){
                count++;
    
            }
    
            public int getCount(){
                return count;
            }
    
            @PostConstruct
            public void init(){
                System.out.println("PrototypeBean.init" + this);
            }
    
            @PreDestroy
            public void destroy(){
                System.out.println("PrototypeBean.destroy");
            }
        }
    }

 

 

 

2. 싱글톤 빈에서 프로토타입 빈 사용?


  • clientBean이라는 싱글톤 빈이 의존관계 주입을 통해서 프로토타입 빈을 주입받는다고 해보자.
  • client는 싱글톤이다. 스프링 컨테이너 생성 시점에 함께 생성, 의존관계 주입 받음
  • clientBean은 자동 의존관계 주입을 사용하는데, 주입 시점에 프토토타입 빈을 요청함.
  • 스프링 컨테이너는 prototypeBean을 생성해서 clientBean에 return함. 이 때 count = 0
  • 그러면 clientBean은 프로토타입 빈은 내부 필드에 prototypeBean의 참조값을 보관.
  • clientBean은 싱글톤이기 때문에 항상 같은 인스턴스를 반환한다.
  • clientA, clientB가 clientBean을 요청하면 이에 해당하는 prototypeBean은 항상 @x01이 리턴될듯?

  • client A가 clientBean의 로직을 호출한다.
  • 해당 로직은 clientBean와 의존관계에 있는 prototypeBean의 count를 증가시킨다.

 

  • 이번엔 client B가 clientBean을 받는다.  싱글톤이기 때문에 같은 인스턴스를 받는다.
  • 이 때! 위에서 예상한 것과 같이 prototypeBean은 이미 clientBean생성시 주입이 끝났다.
  • 즉 싱글톤 내부에 있는 prototypeBean은 한번 주입된 후에 바뀌지 않는다.
  • 좀더 풀어 설명하면 처음 싱글톤 빈(client bean)생성시 싱글톤 빈이 스프링 컨테이너에 프로토타입 빈 요청!
  • 이후 다른 클라이언트가 싱글톤 빈을 요청할 때는 이미 프로토타입빈의 주입이 완료되었음.
  • 싱글톤에 DI가 완료된 후 스프링 컨테이너에 프로토타입 빈을 요청할 일이 없다.
  • 즉 한마디로 싱글톤 빈은 항상 같은 인스턴스를 반환한다!

 

 

3.Test


public class SingletonWithPrototypeTest1 {

    @Test
    public void  prototypeFind(){

        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
        PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
        prototypeBean1.addCount();
        Assertions.assertThat(prototypeBean1.getCount()).isEqualTo(1);

        PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
        prototypeBean2.addCount();
        Assertions.assertThat(prototypeBean2.getCount()).isEqualTo(1);
    }


    @Test
    void singletonClientPrototype(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);

        ClientBean clientBean1 = ac.getBean(ClientBean.class);
        int count1 = clientBean1.logic();
        Assertions.assertThat(count1).isEqualTo(1);

        ClientBean clientBean2 = ac.getBean(ClientBean.class);
        int count2 = clientBean2.logic();
        Assertions.assertThat(count2).isEqualTo(2);
    }

    @Component
    @Scope("singleton")
    static class ClientBean{
        private final PrototypeBean prototypeBean;

        @Autowired
        public ClientBean(PrototypeBean prototypeBean) {
            this.prototypeBean = prototypeBean;
        }
        
        public int logic(){
            prototypeBean.addCount();
            return prototypeBean.getCount();
        }
    }

    @Component
    @Scope("prototype")
    static class PrototypeBean{
        private int count = 0;

        public void addCount(){
            count++;

        }

        public int getCount(){
            return count;
        }

        @PostConstruct
        public void init(){
            System.out.println("PrototypeBean.init" + this);
        }

        @PreDestroy
        public void destroy(){
            System.out.println("PrototypeBean.destroy");
        }
    }
}

 

 

흠.. 프로토타입 빈을 매번 새로 생성하고싶은데...싱글톤 내부에서 사용하면 매 번 생성하지 못한다. 의도가 아니야

도움!

 

4. GitHub : 210730 singletonBean에서 prototypeBean 사용


 

 

GitHub - bsh6463/SpringCoreFunction

Contribute to bsh6463/SpringCoreFunction development by creating an account on GitHub.

github.com

 

'인프런 > [인프런] Spring 핵심원리 이해' 카테고리의 다른 글

웹 스코프, provider  (0) 2021.08.01
Provider, ObjectProvider  (0) 2021.08.01
빈 스코프??  (0) 2021.07.30
@PostConstruct, @PreDestroy  (0) 2021.07.30
빈 생명주기 : @Bean(initMethod, destroyMethod)  (0) 2021.07.30
Comments