반응형

1. 개요

의존 관계를 외부에서 주입(Dependecy Injection(DI))받는 것이 아닌, 직접 필요한 의존 관계를 찾는 것을 의존관계 조회(탐색) (Dependency Lookup(DL)) 이라고 한다. Spring 의 Application Context 전체를 주입받게 된다면, Spring Container 에 종속적인 코드가 되고, 그로 인해 단위 테스트도 어려워지게 된다. 이 때 필요한 것이 의존 관계 조회이다.

 

2. 본론

Spring 에서는 ObjectProvider 인터페이스로 DI Container 에서 해당 객체를 찾아 반환해준다.

DI Container 로 관리되는 Bean 객체들이 서로 의존성으로 엮여 있다면, 단위 테스트하기 많이 불편해지는데 해당 객체에서 필요한 객체들만 가지고 와 테스트하거나 의존성을 맺을 수 있므로 엄청난 이점을 가져다 준다. 사용방법은 단순하다.

 

ObjectProvider<찾고자 하는 클래스> testProvider = new ObjectProvider<>();

찾고자 하는 클래스 test = testProvider.getObject()

 

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

public class SingletonWithPrototypeTest1 {

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

        PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
        prototypeBean2.getCount();
        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(1);
    }

    @Scope("singleton")
    static class ClientBean {

        @Autowired
        private ObjectProvider<PrototypeBean> prototypeBeanProvider;

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

    @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 destory() {
            System.out.println("PrototypeBean.destory");
        }
    }
}

 

스프링의 ObjectProvider 말고도 JSR330 Provider 자바 표준 프로바이더도 있다.

implementation 'javax.inject:javax.inject:1' 만 의존성 추가해주면 사용이 가능하고 앞에 구문에서 ObjectProvider 를 Provider 로 수정하면 된다.

반응형

+ Recent posts