스프링을 막 공부하기 시작하는 비기너에게 DI와 IOC에 대한 개념은 너무나도 중요한 것 같습니다!
하지만, 이를 왜 사용할까요? DI와 IOC를 활용하면 어떤 이점이 있을까요?
Spring에서는 DI와 IOC가 어떻게 이루어지고 있을까요?
위에 물음에 답을 해 보는 시간을 가져보려고 합니다!'
1. DI(Dependency Injection)이란?
먼저, 한 사람이 폰을 구매하는 코드를 같이 살펴봅시다!
public class Main {
public void main(String[] args) {
Person jobth = new Person(“잡th”);
jobth.buy();
}
}
class Person {
…
void buy() {
SamsongPhone samsong = new SamsongPhone(“삼송”);
System.out.println(name + "님이 " + samsong.getName() + “폰을 샀습니다.”);
}
…
}
Person 클래스에서 buy()메서드를 통해, 삼송폰을 구매할 수 있습니다!
폰을 구매하면, 삼송폰을 구매했다는 메세지도 알려주네요!
그런데, 세상에는 삼송폰만 존재하는 게 아니라 사과폰도 존재하지 않나요? 제가 작성해둔 코드로는 Person은 영영
사과폰을 구매할 수 없게 됩니다.
다시 말해서, 어떤 폰을 구매할지 Person에게 선택권이 없이 정해져 있는 코드라는 점에서 한계가 명확합니다.
그렇다면, 다음 코드를 살펴볼까요?
public class Main {
public void main(String[] args) {
Person jobth = new Person(“잡th”);
Phone samsong = new SamsongPhone(“삼송”);
jobth.buy(samsong);
}
}
class Person {
…
void buy(Phone phone) {
System.out.println(name + "님이 " + phone.getName() + “폰을 샀습니다.”);
}
…
비슷하지만, 이번에는 SamsungPhone 객체가 main 메서드 안에서 만들어지고 있습니다.
그리고 buy라는 메서드를 통해 Person 타입의 객체로 전달되고 있네요!
오, 이런 방법으로 한다면, Phone 타입의 파라미터로 전달받을 수 있는 핸드폰의 종류가 삼송폰이든, 사과폰이든, 혹은 다른 폰이든 상관이 없을 것 같지 않나요?
결국 Person은 원하는 폰을 자유롭게 구매할 수 있게 되었네요!
그렇다면, 위 두 코드의 차이는 정확히 뭐라고 정의할 수 있을까요?
자세히 살펴보니, 한가지 다른 점은 첫 번째 코드는 객체 생성을 Person 내부에서 하고, 두 번째 코드는 객체 생성이 Person 외부에서 이루어졌다는 점을 알 수가 있습니다.
정리하자면 필요한 의존성을 외부에서 주입하도록 하니, 더욱 자율적인 Person 객체가 되었다. 뭐 요렇게 정리할 수 있겠죠.
의존성이란?
갑자기 의존성이라는 단어를 사용해서 죄송해요! 하지만 의존성은 말 그대로,
만약 A가 B에 의존한다면, B가 변경 시에 파급효과가 A에도 영향을 미친다는 의미입니다.
파라미터나 리턴값 또는 지역변수 등에서 다른 객체를 참조하는 것을 의미해요!
객체지향 세계에서는 객체들끼리 협력을 하기 위해서는 결국 서로에게 의존할 수 밖에 없는데요,
만약 어떤 하나의 객체가 너무 많은 의존 관계를 갖고 있다면, 해당 객체가 변경되면 파급효과가 그만큼 클 것입니다.
따라서, 불필요한 의존관계는 줄이는 것 또한 매우 중요하겠죠~?
사실 위에 올려드린 두번째 코드에서 눈여겨 봐야 할 점이 하나 더 있는데요,
public class Main {
public void main(String[] args) {
Person jobth = new Person(“잡th”);
Phone samsong = new SamsongPhone(“삼송”);
jobth.buy(samsong);
}
}
class Person {
…
void buy(Phone phone) {
System.out.println(name + "님이 " + phone.getName() + “폰을 샀습니다.”);
}
…
삼송폰의 Type이 SamsungPhone이 아니고, Phone 타입으로 정의되어 있다는 점입니다!
Phone은 모든 폰의 공통적인 속성을 지니고 있는 부모 클래스, 혹은 인터페이스일 텐데
여기서는 인터페이스라고 가정하고 글을 이어 나가 볼게요.
특정한 구현체에 의존하지 않고 인터페이스에게 의존하는 것이 의존성과 결합도를 낮추어 주기 때문에
더욱 변경에 용이한 코드를 작성할 수 있게 됩니다.
하지만 왜 그럴까요?
인터페이스에 의존하는 경우, 실제로 어떤 구현체가 파라미터로 넘어올지 런타임에서 결정되게 됩니다.
이를 어려운 말로 컴파일 의존성과 런타임 의존성이 다르다고도 표현하는데요..ㅎ
이런 경우 해당 인터페이스를 구현하는 모든 구현체 타입을 상황에 맞게 전부 수용할 수 있습니다.
따라서 결합도가 낮아져 변경에 유연한 설계로 이어질 수 있는 것이죠!
제어의 역전(IoC) : Inversion of Control
제어의 역전이란, 결국 방향성에 관련된 이야기입니다.
기존에는 프로그래머가 모든 객체에 대해서 생성부터 소멸까지 모두 관리를 했다면, 제어의 역전이라는 관점에서는 프로그래머가 더 이상 객체에 대한 관리 책임을 지지 않는 것을 의미합니다.
그렇다면 누가 이를 관리할 수 있을까요? 위의 코드에서는 Main 메서드가 이를 담당하고 있습니다.
Person 클래스의 buy메서드를 보면, 해당 파라미터를 통해 주입되는 객체가 정확히 어떤 타입인지는 모릅니다.
어떤 객체를 주입해서 서로 의존 관계를 생성할지에 대한 것은 모두 외부에서 결정되죠.
이는 프로그래머와 Spring 프레임워크간의 관계에도 통용되는 이야기입니다.
Java 언어를 이용한 웹 개발을 할 때, 객체를 관리하는 책임을 프로그래머가 아닌, Spring 프레임워크가 별도로 관리를 하다가, 프로그래머가 특정 객체가 필요한 시점에 Spring 프레임워크에게 받아서 쓸 수 있는 것이죠.
즉 제어의 흐름이 Spring 프레임워크에서 프로그래머로 역전된 상태라고 볼 수 있겠네요.
이렇게 Spring에서 별도로 관리하는 객체를 Spring Bean(빈) 이라고 부릅니다.
또한, 스프링에서 빈 객체를 관리하는 주체를 Spring IoC 컨테이너, 혹은 스프링 컨테이너라고 부릅니다.
이렇게 DI와 IOC가 무엇인지 알아봤는데, 장점은 무엇이 있을까요?
1. DI를 이용하면 생성과 구현을 분리할 수 있다는 이점이 있습니다. 의존관계를 주입받는 클래스에서는
오직 구현에만 집중할 수 있게 됩니다. 이를 통해 단일 책임 원칙(SRP)를 지킬 수 있습니다.
2. DI를 활용하면, 런타임 의존성을 갖게 됩니다. 결과적으로 결합도가 낮아지고 변경이 용이한 프로그래밍을 할 수 있습니다. 또한, 인터페이스를 활용하여 여러 타입의 구현체들을 주입받을 수 있으므로, 확장 가능성은 얼마든지 열려 있습니다.
따라서, 개방 폐쇄 원칙(OCP)를 지킬 수 있습니다.
코드 출처
'CS > Spring' 카테고리의 다른 글
[Spring] DI의 세 가지 방법(필드 주입, 생성자 주입, setter 주입) (0) | 2023.04.21 |
---|---|
[Spring] 스프링에서 빈 객체를 등록하는 방법(@Bean, @Component) (0) | 2023.04.14 |
[Spring] 비즈니스 로직이란? (0) | 2023.04.08 |
[Spring] Controller, Service, Repository (0) | 2023.04.08 |
[Spring] Entity, DTO, VO 무슨 차이야? (0) | 2023.04.07 |