인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

신동훈님의 프로필 이미지
신동훈

작성한 질문수

스프링 핵심 원리 - 기본편

IoC, DI, 그리고 컨테이너

혹시 지금까지 제가 이해한 내용이 올바른건지 궁금합니다

작성

·

345

4

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit#heading=h.w2tomwsznga7)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://docs.google.com/document/d/1xCQKit-1V6l6ObeCe49St33RHPzLF_P_c3o7aSDTKs0/edit#heading=h.7dhnp46ven0v)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]

💡 DI (Dependency Injection) - 의존관계 주입

의존하는 객체를 직접 생성하는 것이 아니라, 외부에서 생성한 후 주입하는 것.

3가지 조건이 필요

  • 클래스 모델이나 코드에는 런타임(실행) 시점의 의존관계가 드러나지 않는다. (= 정적인 클래스 의존관계가 아니다)(= 동적인 객체 인스턴스 의존관계이다) => 인터페이스에만 의존하고 있어야 한다
  • 런타임 시점의 의존관계는 외부에서 결정한다
  • 외부에서 실제 구현 객체(사용할 오브젝트에 대한 레퍼런스)를 생성하고 클라이언트(사용할 오브젝트)에 전달(주입)함으로써 의존관계가 연결되는 것이다

예를 들어 private Car myCar = new 벤츠(); => Car가 인터페이스고 벤츠가 구현 객체라면, 런타임 이전에, 즉 코드상으로 벤츠 클래스를 의존하는 것을 알 수 있다

private Car myCar; => 이러면 Car에 대해 무슨 차가 들어올지 알 수 없다.(런타임 시점의 의존관계가 드러나지 않으므로) => 즉 이렇게 인터페이스에만 의존하고 의존관계 주입이 발생할 수 있다.

💡 IoC (Inversion of Control) - 제어의 역전

프로그램의 제어 흐름(ex:메소드나 객체의 호출작업)을 개발자가 결정하는 것이 아니라, 외부에서 결정(관리)하는 것.

즉 객체를 개발자가 Member member = new Member(); 이런식으로 만드는 것이 아니라, 스프링이 스스로 객체를 생성해서, 필요한 곳에 사용할 수 있게 해줌!
1
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
cs
위 코드 단 하나만 실행했을 뿐인데, 우리는 ac.getBean을 통해, 원하는 객체를 사용할 수 있음!!!!!
참고로 DI도 제어의 역전에 포함되는 기술이며, IoC는 좀더 광범위하게 쓰인다!

🧾 부분 정리

스프링은 IoC, DI와 같은 기술을 사용함으로써

자바만으로는 DIP(의존관계 역전 원칙)와 OCP(계방-폐쇠 원칙)을 지켜가며 객체지향적으로 설계하는데 어려움이 있었는데, 이를 해결.

즉 스프링을 사용하면 좋은 객체 지향 애플리케이션을 개발하기 편해지며, 스프링은 이를 도와주는 프레임워크.

스프링이 좋은 객체 지향 애플리케이션을 개발하는데 도움을 주는 프레임워크인 것 처럼, 스프링 부트스프링의 기술들을 좀 더 편리하게 사용하는데 도움을 주는 프레임워크.

 

제가 정리한 내용들인데, 혹시 맞게 이해한건지요.. 너무 어려워서 여러차례 강의 반복하여 들으며 정리했습니다

답변 2

0

신동훈님 글 잘봤습니다. 감사합니다 그런데 궁금증이 생겼습니다.

'예를 들어 private Car myCar = new 벤츠(); => Car가 인터페이스고 벤츠가 구현 객체라면, 런타임 이전에, 즉 코드상으로 벤츠 클래스를 의존하는 것을 알 수 있다'

부분에서 벤츠 클래스를 의존하는 것 알 수 있다고 적혀 있는데, 반대가 아닌가요? 벤츠 클래스가 Car인터페이스를 의존하고 있는게 아닌가? 하는 궁금증이 생겨 이렇게 올리게 되었습니다.

신동훈님의 프로필 이미지
신동훈
질문자

안녕하세요. 제가 감히 답을 할 수 있을지는 모르겠지만, 우선 벤츠 클래스는 당연히 Car 인터페이스의 구현체이기에 Car 인터페이스에 의존적인것이 당연합니다. 또한 이는 DIP를 어긴 것이 아닙니다.

private Car myCar = new 벤츠();

해당 코드가 벤츠 클래스를 의존하고 있다는 것을 알 수 있다는 것은 해당 코드가 사용된 클래스가 벤츠 클래스에 의존하는 것을 알 수 있다는 뜻이었습니다.

예를 들면 다음과 같겠지요

public class CartRider {

private Car myCar = new 벤츠();

...

}

(클래스 이름이 마땅히 생각나지 않아서 아무렇게나 적었습니다.)

위 코드를 통해 CartRider는 Car(인터페이스)와 벤츠(구현체)에 모두 의존적이라는것을 알 수 있습니다. 그리고 이는 추상화에도 의존하며 구체화에도 의존하므로 DIP를 위반하는 코드가 되어버립니다.

 

따라서 이를 해결하기 위해 다음과 같은 방법을 사용합니다.

public class CartRider {

private Car myCar ;

public CartRider(Car car){

            this.myCar = car;

}

...

 

}

이렇게 코드를 작성하게 되면 CartRider는 벤츠에 의존적이지 않고, Car에만 의존적이게 바뀌게 됩니다.

또한 이는 추상화에만 의존한 코드이므로 DIP를 위반하지 않습니다.

그리고 해당 클래스를 사용할 때는 외부에서 생성자를 통해 Car 구현체를 주입해주며, 이를 의존관계 주입(DI)이라고 부릅니다.

 

(제가 공부했던 내용들을 토대로 작성한 글이기에 틀린 부분이 있을 수 있습니다. 감사합니다)

0

안녕하세요. 신동훈님, 공식 서포터즈 OMG입니다.

정리를 정말 잘 하시네요^^

제가 봤을 때 내용 상 문제점은 없어보입니다.

하신것처럼 전체 강의를 정리하면 완강 후엔 엄청난(?) 실력 성장을 하시게 되었을 거라 확신합니다^^

 

감사합니다.

신동훈님의 프로필 이미지
신동훈

작성한 질문수

질문하기