스프링/1. 스프링 핵심 원리

47강. 프로토타입빈을 싱글톤 빈과 사용할 때 문제

sdafdq 2023. 7. 24. 21:25

기본적으로 프로토타입 빈을 쓴다는 것은 사용할 때 마다 새롭게 생성해서 사용하려는 의도임.

 

public class SingletonWIthPrototypeTest1 {
    @Test
    void prototypeFind(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
        PrototypeBean prototypeBean1 = new PrototypeBean();
        prototypeBean1.addCount();
        assertThat(prototypeBean1.getCount()).isEqualTo(1);

        PrototypeBean prototypeBean2 = new PrototypeBean();
        prototypeBean2.addCount();
        assertThat(prototypeBean2.getCount()).isEqualTo(1);
    }

    @Test
    void singletonClientUsePrototype(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
        ClientBean clientBean1 = ac.getBean(ClientBean.class);
        int count1 = clientBean1.logic();
        assertThat(count1).isEqualTo(1);

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

    @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();
        }
    }

    @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");
        }

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

위 같은 경우 싱글톤 빈이 프로토타입 빈을 가지고 사용하는 경우인데, 뭐 당연하게도 이미 싱글톤 빈에 의존관계 주입을 해줬기 때문에 계속해서 프로토타입 빈이 싱글톤 빈 안에 남아있음.

프로토타입 빈을 사용하려는 의도인 호출할 때마다 새로 생성과는 거리가 멈.

 

뭐 굳이 제대로 프로토타입은 호출할 때마다 새로 생성하게끔 하려면

    @Test
    void singletonClientUsePrototype(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
        ClientBean clientBean1 = ac.getBean(ClientBean.class);
        int count1 = clientBean1.logic();
        assertThat(count1).isEqualTo(1);

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

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

        @Autowired
        ApplicationContext ac;

//        @Autowired
//        public ClientBean(PrototypeBean prototypeBean){
//            this.prototypeBean = prototypeBean;
//        }

        public int logic(){
            PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
            prototypeBean.addCount();
            return prototypeBean.getCount();
        }
    }

이렇게 하면 되긴 하는데.. 

이렇게 스프링 컨텍스트 전체 주입받는 건 컨테이너에 종속적인 코드가 되고 단위 테스트도 어려워 짐.

 

 

 

물론 참고로, 주입받는 시점에서 여러 빈에서 같은 프로토타입 빈을 주입받으면, 그 때는 계속 새로 생성한다. 

 

 

 

 

'스프링 > 1. 스프링 핵심 원리' 카테고리의 다른 글

49강. 웹 스코프  (0) 2023.07.24
48강. Provider  (0) 2023.07.24
46강. 프로토타입 빈.  (0) 2023.07.24
45강. 빈 스코프  (0) 2023.07.23
44강. @PostConstruct, @PreDestroy 로 콜백  (0) 2023.07.23