스프링 프레임워크의 가장 기본적인 능력은 객체를 생성해 주고 객체들을 조립해 주는 능력을 얘기한다. 즉, DI(Dependency Injection)와 IoC 컨테이너를 통해 스프링은 객체를 생성하고, 객체 간의 의존성을 관리해준다.
DI(Dependency Injection)는 '의존성 주입'이라고 번역된다. 처음에 의존성 주입이라고 들으면 난해하고 어렵게 생각될 수 있기 때문에 쉽게 DI는 부품을 조립하는 방식으로 생각하면 좋다.
DI(Dependency Injection), IoC Container
DI(Dependency Injection)의 의미를 알아보자. 우리가 객체지향으로 프로그램을 만들게 될 경우 프로그램은 객체들의 조립 관계를 통해서 만들어지게 된다. 아래 그림을 보면 A 클래스를 정의하면서 A클래스가 B 클래스를 이용하고 있다. 단순하게 클래스를 이용하는 것이 아니라 B클래스를 객체화해서 사용하고 있다.
그래서 객체 지향 프로그래밍에서 클래스 간의 관계는 여러 형태로 존재할 수 있다. 그 중 하나가 has-a 관계로, 이는 한 클래스가 다른 클래스를 소유하거나 사용할 때 사용된다. has-a 관계는 일체형(Composition)과 조립형(Association)으로 나눌 수 있다.
왼쪽의 Composition has a 관계는 A 클래스가 B 클래스를 사용할 때, A 클래스가 직접 B 객체를 생성하여 내부에서 사용하는 방식이다. 즉, A가 B를 소유하며, B 객체는 A 객체의 생성과 함께 만들어진다. 그래서 이것을 A가 B를 일체형으로 가졌다라고 해서 일체형 has a 관계라고 한다.
오른쪽의 Association has a 관계는 A 클래스가 B 클래스를 사용할 때, A클래스가 직접 B 객체를 생성하지 않고 B 객체를 A 클래스 외부에서 생성하고, A 클래스는 B 객체를 주입(Injection)받아 사용하는 방식이다. A가 B를 가졌기 때문에 B를 A의 부품이라고 생각해도 되는데 이런 부품을 다른 사람들은 Dependency 또는 종속 객체, 종속성이라고 한다. 그리고 이 부품을 조립, 꽂는 작업을 주입(Injection)이라고 한다.
그래서 Composition has a 같은 경우에는 일체형으로 부품을 가지고 있는것이고 Assocation has a는 조립형으로 부품을 주입받아 쓰는 즉 DI라고 봐도된다.
HAS-A는 포함관계를 의미한다. (~는 ~을 가지고 있다.)
IS-A는 상속관계를 의미한다. (~는 ~이다.) (ex: 경찰차는 차다., 사람은 동물이다.)
아래 그림의 위에 있는 프로그램은 일체형에 대한 내용이고 밑에는 조립형에 대한 내용이다. 일체형(Composition) 방식은 한 객체가 다른 객체를 직접 생성하여 사용하기 때문에, 두 객체 간의 결합도가 매우 높다. 즉, 프로그램의 유지보수나 확장성이 떨어진다. 반면에, 조립형(Association) 방식은 외부에서 의존 객체를 주입하여 결합도를 낮추기 때문에, 프로그램을 더 유연하게 관리할 수 있다.
일체형 방식에서는 객체가 내부적으로 부품(의존성)을 생성하여 사용하므로, 사용자 입장에서 해당 객체가 어떤 부품을 사용하는지 잘 모르고 쉽게 바꿀 수도 없다. 하지만 조립형에서는 외부에서 부품을 주입하기 때문에, 사용자가 필요한 부품을 쉽게 교체할 수 있고, 업데이트도 용이하다. 하지만 조립형에서는 부품을 준비하고 조립 즉 주입해야 하는 불편함이 존재한다.
DI는 Setter Injection과 Constructor Injection이라는 두 가지 방법으로 주입할 수 있다. Setter Injection는 Setter 메서드를 사용하여 의존성을 주입하는 방식이고 Constructor Injection는 생성자를 사용하여 의존성을 주입하는 방식이다.
// Setter Injection
class A {
private B b;
public void setB(B b) {
this.b = b;
}
}
A a = new A();
B b = new B();
a.setB(b); // Setter를 통해 B 객체를 주입
----------------------------------------------
// Constructor Injection
class A {
private B b;
public A(B b) {
this.b = b;
}
}
B b = new B();
A a = new A(b); // 생성자를 통해 B 객체를 주입
오늘 배운 DI(Dependency Injection)를 이해하기 쉽게 설명하자면, 조립형 컴퓨터를 구입하는 것과 비슷하다. 컴퓨터를 살 때 일체형으로 살 수도 있지만 조립형으로 직접 필요한 부품을 선택하여 최적의 성능을 낼 수 있는 시스템을 만들 수 있다. 조립형 컴퓨터의 장점은 성능을 최적화하거나, 필요에 따라 부품을 쉽게 교체할 수 있다는 것이다. 하지만, 조립하는 과정이 불편하거나 어려울 수 있다.
그렇다면, 이런 불편함을 해결할 방법은 무엇일까? 바로 조립을 해주는 서비스를 이용하는 것이다. 소정의 비용을 지불하면, 전문가가 원하는 부품을 조립해주어 시간도 절약되고, 직접 조립하는 불편함을 겪지 않아도 된다.
소프트웨어에서 이러한 조립 역할을 하는 것이 바로 DI(Dependency Injection)이며, 이를 구현하는 대표적인 프레임워크가 스프링(Spring)이다. 스프링은 객체(부품)를 생성하고 조립해주는 역할을 한다. 즉, 개발자가 어떤 부품(객체)을 필요로 하는지만 설정하면, 스프링이 그 부품들을 조립해서 결과물을 제공해주는 것이다.
스프링의 DI 기능을 통해 우리는 객체 간의 복잡한 의존성 관리와 결합을 손쉽게 할 수 있다. 직접 객체를 생성하고 결합하는 번거로움을 덜고, 스프링이 이를 자동으로 처리해주므로, 우리는 결과물만 사용하면 된다. 이것이 스프링을 사용하는 가장 기본적인 이유이다.
다음 시간에는 이 객체를 조립해 주는데 필요한 IOC 컨테이너에 대해서 알아보도록 하자.
참고자료
[1] 유튜브 채널 뉴렉처 - 스프링 프레임워크 강의 3강 - DI(Dependency Injection)
'🖥️ Backend > Spring' 카테고리의 다른 글
[Spring] 6.스프링 DI 설정을 위해 이클립스 플러그인 설치하기 (3) | 2024.10.20 |
---|---|
[Spring] 5.Spring없이 Dependency를 직접 Injection하기 (0) | 2024.10.08 |
[Spring] 4.IoC(Inversion Of Control) 컨테이너 (1) | 2024.10.02 |
[Spring] 2.느슨한 결합력과 인터페이스 (0) | 2024.09.30 |
[Spring] 1.Spring 소개와 학습 안내 (1) | 2024.09.27 |