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

48강. Provider

sdafdq 2023. 7. 24. 22:07

앞서 말한 프로토타입과 싱글톤과 같이 쓸 시 프로토타입의 사용목적과 맞지 않는 곳은 Provider로 해결

    @Scope("singleton")
    static class ClientBean{
        private final ObjectProvider<PrototypeBean> prototypeBeanProvider;

        @Autowired
        public ClientBean(ObjectProvider<PrototypeBean> prototypeBeanProvider){
            this.prototypeBeanProvider = prototypeBeanProvider;
        }

        public int logic(){
            PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
            prototypeBean.addCount();
            return prototypeBean.getCount();
        }
    }

이건 Spring에서 제공해주는 기능이다. 따지자면 ac.getBean()해주는 거랑 똑같다. 

 

의존관계 주입을 DI 디펜던시 인젝션 이라고 하고,

의존관계 조회를 DL 디펜던시 룩업 이라고 하는데

Provider가 바로 그걸 제공해 주는 거다. 그래서 사실 프로바이더는 프로토타입 전용이라기 보다는 프로토타입을 제공받기 편하다. 그래서 아마 싱글톤으로 하면 똑같이 싱글톤으로 되겠지..? 어차피 같은 컨테이너에서 조회해서 가져와주는 거니..

 

ObjectProvider 의 getObject() 를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반 환한다. (DL)

 

ObjectFactory도 있는데, 이거는 딱 getObject만 있다. ObjectProvider는 저걸 상속받아 여러 편의기능과 함께 만들어진것. 

 

단점은 당연히 스프링 꺼라 스프링에 의존한다.

 

 

 

JSR-330 Provider

이거는 자바 표준이다. 그래서 스프링 말고도 다른 컨테이너에서도 쓸 수 있다. 단, 라이브러리를 추가 해야 함..

 

implementation 'jakarta.inject:jakarta.inject-api:2.0.1'

build.gradle에 추가시켜 주면 됨.. 디펜던시.. 그러니까 내가 만드는 이 프로젝트에 종속되어지는 라이브러리에 추가시켜 주면 됨..

 

참고로 이거 굉장히 심플함.

 

들어가 보면

public interface Provider<T> {

    /**
     * Provides a fully-constructed and injected instance of {@code T}.
     * @return instance of {@code T}.
     *
     * @throws RuntimeException if the injector encounters an error while
     *  providing an instance. For example, if an injectable member on
     *  {@code T} throws an exception, the injector may wrap the exception
     *  and throw it to the caller of {@code get()}. Callers should not try
     *  to handle such exceptions as the behavior may vary across injector
     *  implementations and even different configurations of the same injector.
     */
    T get();
}

이것만 있음. get()만 쓰면 됨.

자바 표준에다 간단해서 모조 객체 만들어서 단위테스트 하기 편함.

 

 

    @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 Provider<PrototypeBean> prototypeBeanProvider;

        @Autowired
        public ClientBean(Provider<PrototypeBean> prototypeBeanProvider){
            this.prototypeBeanProvider = prototypeBeanProvider;
        }

        public int logic(){
            PrototypeBean prototypeBean = prototypeBeanProvider.get();
            prototypeBean.addCount();
            return prototypeBean.getCount();
        }
    }

 

 

근데, 사실 프로토타입 쓰는 경우는 거의 없음. 솔직히 말해 리소스 낭비이기도 하고.. 대부분 싱글톤으로 가능..

 

 

 

스프링의 ObjectProvide vs Provider

Provider는 별도로 라이브러리 추가해야 되지만 그거정도야 뭐..

 

그리고 보통 자바 표준과 스프링이 제공해주는 기능이 겹칠 때가 있는데..

그 때는 다른 컨테이너 사용할 일 없으면 보통 스프링꺼 쓰긴 함.. 스프링이 워낙 잘 되어있고, 또 어떤 기능들 경우에는 애초에 스프링이 종속라이브러리로 가지고 있는 경우, 아예 쓰라고 자바표준을 권장하기도 함.

 

 

 

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

50강. request 스코프  (0) 2023.07.25
49강. 웹 스코프  (0) 2023.07.24
47강. 프로토타입빈을 싱글톤 빈과 사용할 때 문제  (0) 2023.07.24
46강. 프로토타입 빈.  (0) 2023.07.24
45강. 빈 스코프  (0) 2023.07.23