⌨️ DI에 대한 이해
의존성 주입 혹은 의존 관계 주입에 대해 사전적 문서적인 이해가 아닌 나에게 필요한 방식의 이해를 위한 공부와 고찰 진행
비유적인 표현이 아닌 DI 자체를 확실히 인지하는 것이 목표.
1. 의존관계와 DI
1.1. 의존관계
DI를 알기 전에 우선 의존관계 부터 짚고 가야 할 것 같다.
의존관계는 뜬금없이 Java Spring 에서 나온 개념이 아니다. 원래 OOP에서 통용되던 개념이다.
우리는 하나의 클래스에서 다른 클래스를 활용하고 싶을 때 'new'를 통해 객체를 생성해서 사용했다.
이때 클래스의 객체를 생성해서 참조하게 되면 의존관계가 성립되는 것이다.
위 그림 처럼 ProductController에서 ProductService의 기능을 사용할 때, 의존한다고 표현한다.
의존 관계의 종류 또한 여러가지가 있으나, 본문은 DI에 더 중점을 두고 작성하기 때문에 넘어가도록 한다.
1.2. DI
위의 상황에서 의존 관계는 맺었지만 의존성 주입은 이뤄지지 않은 상태이다. 두 예시를 보자
public class ProductController {
public static void main(String[] args){
ProductService productService = new ProductService();
}
}
public class ProductService{
public getProduct(){
return null;
}
}
일반적으로 다른 클래스의 객체를 사용하기 위해 'new'를 통해 클래스를 생성해서 쓰는 형태이다.
이 경우 의존 관계만 성립이 되어있다. 주입을 위해선
public class ProductController {
private ProductService productService;
public ProductController(ProductService productService){
this.productService = productService;
}
}
와 같은 형태로 생성자를 통하여 객체를 전달 받으면 된다. 쉽게 말해
위와 같이 생성자를 통해 클래스의 외부에서 객체를 전달 받는 것을 DI 라 한다.
1.2. 🌟외부란??
내가 생각하기에 DI 개념 가장 중요한 부분이라 생각한다.
일반적인 경우를 생각해보자.
스프링을 공부하셨네요? DI에 대해서 설명해 주실 수 있나요?? 란 질문에 나는 유창한 대답을 할 것이다.
~~~ 해서 클래스의 외부에서 객체를 전달 받는 것을 DI라고 합니다.
혹시 외부는 어디죠?? 라는 질문이 이어졌을 때 말문이 턱 막혔다.
이 포스팅을 쓰는 주된 이유기도 하다.
다시 위와 같이 두 가지의 경우를 나눠서 보자
public class ProductClient{
public static void main(String[] args){
ProductService productService = new ProductService();
ProductController productController = new ProductController(productService);
}
}
이 경우 외부는 ProductClient 가 된다 ProductClient 가 new를 통해 ProductController를 만들면서 productService에 대한 의존성을 주입해주고 있다.
아니 근데 'new'를 쓰지 않고 생성자를 통해 객체를 전달해주는 거라면서요??
맞다 우리는 이해와 학습을 통해 이제서야 Spring에서 왜 DI가 중요하고 핵심 기술인지에 도달한 것이다.
스프링 프레임워크에서는 외부가 바로 스프링이다. 스프링의 DI 컨테이너가 자동으로 의존성 주입( 자동이란 표현을 썼지만 안에서 순차적인 동작은 다 이루어짐 단지 개발자 관점에서의 자동)을 해주기 때문이다.
public class ProductClient{
public static void main(String[] args){
GenericApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
ProductController productController = context.getBean(ProductController.class);
}
}
위 코드와 달리 ProductController 를 new를 사용하지 않고 사용할 수 있게 됐다.
결국 IoC(제어의역전) 개념이 여기서 나오는 것이다. 프레임워크를 사용했을 때의 생산성 향상을 도와주고 이점을 주는 부분이다.
2. WHY?
2.1. new를 사용하지 않아도 된다.
일반적으로 객체를 생성할 때는 new가 필요하다. 어찌보면 당연한 말이다.
하지만 OOP 관점에서 개발할 때 불편한 점이 생기기 마련이다. 예를 들어 참조할 클래스의 변경이 생길 경우
new를 통해 생성한 모든 클래스를 수정해야 하는 경우가 생긴다.
즉 언제나 확장성과 유연성 재사용성을 고려하여 느슨하게 결합하여 사용해야 한다.
2.2. 클래스간 결합도를 낮춰준다.
2.1에서도 언급했지만 필요충분적인 모습을 보여주는 관계이다. 결국 DI를 제대로 활용하려면 느슨하게 결합을 해야 하고,
DI를 잘 활용한 클래스들은 느슨한 결합도를 보여준다.
2.3. Spring이 의존성 주입을 대신해준다.
막말로, 생성자로 객체를 가져다 쓰는 거야라고만 말해도 될 정도로 Spring에서 의존성 주입을 잘해주고 있다.
생산성이 올라가고, 클래스 간의 결합도를 낮춰주는 데 사용하지 않을 이유가 없다.
3. 피드백
- 외부라고 일컬어지는 DI 컨테이너의 구조와 Spring Bean에 대한 이해를 첨가하면 좋았을 것