IOC를 코드화하는 방법 중 하나가 DI라고 했다.
DI 알아보기
일단 말이 어렵다. 의존성을 주입한다?
의존성: 위에서 이야기한 한 객체 안에 다른 객체가 들어있는 상황을 의미주입: 스프링 컨테이너가 객체 안에 새로운 객체를 넣어준다는 의미
객체를 넣을 때 사용하는 특별한 어노테이션이 존재한다.
Autowired
DI를 구현하는 과정에서 어노테이션 @Autowired가 반드시 들어간다.
@Service
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
}
@Autowired 키워드가 들어가 있으면, 스프링 컨테이너가 주입해야 할 객체(=Bean)을 넣을 준비를 한다고 생각하면 됨.
그럼 스프링 컨테이너는 뭘 보고 빈 객체(=Bean)을 미리 만드는가?
- 설정 파일(예: @Configuration, @ComponentScan 등), 어노테이션(예: @Service, @Repository, @Component, @Controller 등)
의존성 주입 과정
-
Myservice라는 객체는 repository라는 객체에 의존하고 있다. repository가 있어야, Myservice가 제대로 작동할 수 있다.
-
@Autowired를 통해서 스프링 컨테이너 안에서 이미 만들어져 있던 repository 객체를 전달받는다.
-
Myservice 객체의 생성자를 통해 repository 객체가 Myservice 객체 안으로 들어간다.
DI의 방법
DI를 구현하는 3가지 방법을 알아보자.
생성자 주입 (Constructor Injection)
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
}
주입해야 할 객체를 생성자를 통해 넣는 방식.
생성자가 1개라면, @Autowired 어노테이션을 생략할 수 있음.
모든 의존성을 주입받아 불변성을 유지할 수 있고, 필수 의존성을 강제할 수 있습니다. 또한, 테스트가 용이하고, 순환 참조 방지에 도움이 됩니다.
세터 주입 (Setter Injection)
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}
주입해야 할 객체를 setter()를 통해 넣는 방식.
의존성을 선택적으로 주입해야 하거나, 필수적이지 않은 의존성을 주입할 때 유용.
- 의존성이 선택적이다? 객체 안에 객체 중 꼭 필요한 경우가 아닌 경우를 의미.
필드 주입 (Field Injection)
public class MyService {
@Autowired
private MyRepository repository;
}
주입해야 할 객체를 객체 선언 과정에서 넣는 방식.
간단하지만 테스트와 유지보수에 불리하므로, 실무에서는 잘 사용하지 않는 편.