바우처 미션을 진행하면서 근본적인 궁금증이 생겼다. 왜 의존성 주입을 받아야하지? java의 다형성을 통해 충분히 유연한 코드를 작성할 수 있고, 객체 간의 역할을 나눠서 수행하는 거라면 그냥 객체를 생성해서 할 수 있지 않을까?
VoucherConfig voucherConfig = new VoucherConfig();
CommandHandler commandHandler = voucherConfig.commandHandler();
VoucherRepository voucherRepository = voucherConfig.voucherRepository();
이제 Bean으로 등록해 사용해보자.
ApplicationContext context = new AnnotationConfigApplicationContext(VoucherConfig.class);
VoucherConfig voucherConfig = context.getBean(VoucherConfig.class);
CommandHandler commandHandler = voucherConfig.commandHandler();
VoucherRepository voucherRepository = voucherConfig.voucherRepository();
VoucherRepository는 interface이기 때문에 얼마든지 Config 클래스에서 갈아 끼울수 있고, 객체 간의 역할을 잘 분리하여 수행하는 것처럼 보인다. 그러나 테스트코드를 작성하며 voucherRepository가 메소드를 실행하지 않는 이슈를 만났다. 알고보니 Config 클래스에서 voucherRepository를 생성하여 실행하기 때문에 mock 객체로 대체되지 않았다.
사실 저렇게 객체를 생성하여 사용하지 않고 필드로 지정하여 의존성 주입을 받는 건, Spring이 이 귀찮은 일을 다 해주기 때문이다. 스프링이 DI 컨테이너로 불리는 이유이기도 하다. BeanFactory와 ApplicationContext가 클래스를 탐색하고, 객체를 만들며 객체들의 관계까지 설정해준다. 이러한 개념은 제어의 역전(Inversion of Control, IoC)라고 불리기도 한다. 어떠한 객체를 사용할지에 대한 책임은 프레임워크에게 넘어갔고, 자신은 수동적으로 주입받는 객체를 사용하기 때문이다.
private final VoucherService voucherService;
public VoucherApplication(VoucherService voucherService) {
this.voucherService = voucherService;
}
VoucherService에 @Service 어노테이션(들어가 보면 @Configuration이 붙어있다)으로 빈을 등록해 놓으면, 스프링의 DI 컨테이너가 빈을 생성하고 반환한다. Spring이 알아서 객체를 생성하고 주입하므로, 핵심 로직에 집중할 수 있다. 또한 Mock 객체로 대체하여 테스트작성도 가능하게 되었다.
'programming > java, spring' 카테고리의 다른 글
Java의 constant pool (1) | 2023.06.04 |
---|---|
트랜잭션 격리수준과 JPA 낙관적 락을 통한 동시성 제어 (1) | 2023.03.11 |
Hibernate 내부 클래스 PersistentBag (1) | 2023.03.03 |
Spring Security 인증 내부를 파헤쳐보자 (0) | 2023.02.25 |
jacoco를 적용해 테스트 커버리지를 높여보자 (0) | 2023.02.22 |