의존성 주입(Dependency Injection, DI)은 클라이언트가 의존할 대상을 외부에서 지정해 주는 것을 말한다. 이를 통해 클라이언트의 코드 변경 없이 다형성을 구현할 수 있다.
의존성을 주입하기 위해서는 먼저 용도에 따라 클래스에 @Controller, @Service, @Repository, @Component, @Configuration과 같은 Bean을 등록하기 위한 annotation을 부여해야 한다. IoC(DI) Conatainer는 해당 annotation이 부여된 객체들을 관리하며 클라이언트 대신 생성하고, @Autowired가 명시된 클라이언트의 field, constructor, method에 주입한다.
@Repository
public class MenuRepository {
field 주입
field 주입은 field의 타입 객체에 대한 의존성을 주입하는 방식으로서, 가장 간단하고 편리한 방법이다.
@Autowired
private MenuRepository menuRepository;
menuRepository field는 MenuRepository 객체를 참조하며 해당 객체의 method를 호출할 수 있다.
이렇게 편리하게 주입할 수 있다는 막강한 장점이 있지만, framework에 대한 의존도가 너무 높아져 framework가 없으면 아무런 기능을 할 수 없고, 외부에서의 수정이 불가능하여 테스트를 수행하기 어려워진다는 치명적인 단점이 있다.
따라서 실제 구현용으로는 잘 쓰이지 않고, 주로 테스트 코드에서 쓰인다.
constructor 주입
constructor(생성자) 주입은 생성자 parameter(매개변수)의 타입 객체에 대한 의존성을 주입하는 방식으로서, 코더가 직접 작성할 분량이 많아 번거로운 방법이다.
private final MenuRepository menuRepository;
@Autowired
public MenuService(MenuRepository menuRepository) {
this.menuRepository = menuRepository;
}
의존성 주입의 대상이 되는 constructor가 하나뿐이면 @Autowired는 생략이 가능하다.
public MenuService(MenuRepository menuRepository) {
this.menuRepository = menuRepository;
}
위의 예시에서는 매개변수가 하나뿐이지만, 매개변수가 많을 경우 직접 작성할 것이 많아 부담이 커지게 된다. 이는 초기화되지 않은 모든 final field를 매개변수로 가지는 생성자를 자동 생성해 주는 @RequiredArgsConstructor를 통해 간소화해 해결할 수 있다.
대부분의 의존관계는 한 번 형성되면 변경할 필요가 없을 뿐만 아니라, 변동되면 안 된다. 생성자는 단 한 번만 호출되고 이는 의존관계의 불변을 보장해 주므로, 대부분의 의존성 주입에서 사용되는 방식이다. 의존관계가 고정돼야 하는 field에 public 접근제한을 가지는 수정자(Setter 등)를 이용하면, 외부 영향에 의해 변동되기 쉬워져 버그 발생 확률이 높아진다. 따라서 constructor 주입을 통해 의존성을 주입하는 것이 가장 바람직하다.
method 주입
method 주입은 method 매개변수의 타입 객체에 대한 의존성을 주입하는 방식으로서, 일반 method에는 거의 쓰이지 않고 주로 Setter에 주입하게 된다.
private MenuRepository menuRepository;
@Autowired
public void setMemberRepository(MenuRepository menuRepository) {
this.menuRepository = menuRepository;
}
DI Container를 통해 의존성을 주입하지 않아도 자체적으로 사용할 수 있도록 유연한 method가 필요하거나, 값의 잦은 변경이 필요한 field인 경우에 적합하다.
@Autowired(required = false)
public void setMenuRepository(MenuRepository menuRepository) {
this.menuRepository = menuRepository;
}
위와 같이 @Autowired 옆에 (required = false)를 추가해, annotation에 의한 의존성 주입이 없어도 사용할 수 있는 유연한 Setter를 선언할 수 있다. 또한 Setter는 생성자와 달리 외부에서 호출할 수 있으므로, 이를 이용해 의존관계를 변경할 수 있다.
그러나 대부분의 의존관계는 처음 주입된 관계로 고정되어 있으므로, 위에서 언급한 외부 영향의 위험성 때문에 잘 사용되지 않는다.
'Development > Spring' 카테고리의 다른 글
REST API의 URI 설계 기본 규칙 (0) | 2023.04.14 |
---|---|
REST API 특징 정리(https://restfulapi.net 참고) (0) | 2023.04.12 |
spring framework에서 사용하는 주요 annotation 정리 (0) | 2023.04.11 |
HTTP method의 개념과 종류 정리 (0) | 2023.04.11 |
DDD 기반의 AOP에서 비즈니스 로직이 가지는 의미 (0) | 2023.04.07 |