#제어의 역전 IoC(Inversion of Control)
- 기존의 프로그램에서는 클라이언트 구현객체가 스스로 필요한 서버 구현 객체를 생성,연결,실행하였다.
: 즉, 구현 객체가 프로그램의 제어 흐름을 스스로 조종하며, 이는 개발자로써 자연스러운 흐름이다.
EX) 클라이언트 구현객체(OrderServiceImpl)에서 서버 구현 객체(MemoryMemberRepository, FixDiscountPolicy)들을 직접 생성하여 실행하였다. 이는 여러가지 객체 지향 설계 원칙을 위반하였다.
- 반면에, AppConfig가 등장한 이후에 클라이언트 구현 객체는 자신의 로직을 실행하는 역할만 담당한다
: App의 전체적인 흐름 제어를 AppConfig에서 담당한다.
EX) OrderServiceImpl 코드에서 필요한 인터페이스들을 호출하나, 어떤 구현 객체가 호출될지는 전혀 알지 못한다.
또한, OrderServiceImpl 객체도 AppConfig가 생성하며, OrderService 인터페이스의 다른 구현 객체를 생성하고 실행할 수 도 있다. 여전히 OrderServiceImpl 객체는 자신의 로직을 실행하기만 한다.
- 기존에는 다음과 같은 순서로 객체가 만들어지고 실행되었다.
: 객체 생성 -> 의존성 객체 생성 -> 의존성 객체 메소드 호출
- 하지만 스프링에서는 다음과 같은 순서로 객체가 만들어지고 실행된다.
1) 객체 생성
2) 의존성 객체 주입
: 스스로 객체를 만드는 것이 아닌, 제어권을 스프링에게 일임하여 스프링이 만들어 놓은 객체를 주입한다.
3) 의존성 객체 메소드 호출.
*** 이렇듯, 프로그램의 제어 흐름을 직접 제어하는게 아닌 외부에서 관리하는 것을 제어의 역전, IoC라고 한다.
= 객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여, 가독성, 코드중복, 유지 보수를 편하게 할 수 있다.
# Framework vs Library
- 프레임워크는 내가 작성한 코드를 제어하고, 대신 실행한다. (JUnit, Spring)
- 반면에, 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 프레임워크가 아니라 라이브러리이다.
#DI, 의존성 주입 (Dependency Injection)
- OrderServiceImpl 클래스에서는 DiscountPolicy, MemberRepository 인터페이스에 의존하지만, 실제 어떤 구현 객체가 사용될지는 전혀 모르고 있는 상태이다.
- 의존 관계는 정적인 클래스 의존 관계와, 실행 시점에 결정되는 동적인 객체(인스턴스) 의존 관계를 분리하여 생각해야 함.
1) 정적인 클래스 의존 관계
: 클래스 내에서 사용한 import 코드만 보고도 의존 관계를 쉽게 파악할 수 있다.
-> 그러나 어떤 구현 객체가 올지는 이것만 보고는 확인이 불가하다.
2) 동적인 객체 인스턴스 의존 관게
: 이는 애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계이다.
- 애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고, 클라이언트에 전달(주입)하여 클라이언트와 서버의 실제 의존 관계가 연결되는 것을 의존관계 주입이라고 한다.
- 외부에서는 객체 인스턴스를 생성하고, 그 참조값을 전달하여 연결된다.
- DI를 사용하면 클라이언트 코드를 변경하지 않고도 클라이언트가 호출하는 객체를 변경할 수 있다.
- 또한, 정적인 클래스 의존 관계는 변경하지 않고 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.
- 클래스 모델이나 코드에는 런타임(실행) 시점의 의존관계가 드러나지 않는다. (= 정적인 클래스 의존관계가 아니다)(= 동적인 객체 인스턴스 의존관계이다) => 인터페이스에만 의존하고 있어야 한다
- 런타임 시점의 의존관계는 외부(AppConfig) 에서 결정한다.
- 외부에서 실제 구현 객체(사용할 오브젝트에 대한 레퍼런스)를 생성하고 클라이언트(사용할 오브젝트)에 전달(주입)함으로써 의존관계가 연결되는 것이다.
#IOC, DI 컨테이너
- AppConfig 처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것을 IoC 컨테이너, 혹은 DI 컨테이너라고 한다.
- Assembler, Object Factory라고도 불린다.
# Spring으로 전환하기
: 지금까지는 순수 자바 코드로 DI를 적용했으나, 이젠 스프링으로 전환해보자.
- AppConfig을 스프링 기반으로 변경
1) AppConfig에 설정을 구성한다는 뜻인 @Configuration을 붙여준다.
2) 각 메소드에 @Bean 을 붙여주면, 스프링 컨테이너에 스프링 빈이 등록된다.
- MemberApp에 스프링 컨테이너 적용
1) ApplicationContext를 통해서 AppConfig의 Bean들을 Spring Container에 넣어서 관리하게 된다.
2) 각 메소드를 사용하고 싶으면 컨테이너에서 getBean(name,Type) 을 통해서 호출해야한다.
- OrderApp에 스프링 컨테이너 적용
# Spring Container
1) 위에서 사용한 ApplicationContext를 스프링 컨테이너라고 한다.
: 기존에는 개발자가 AppConfig를 사용해 직접 객체를 생성하고 DI를 했지만, 이제는 스프링 컨테이너를 통해 사용한다.
2) 스프링 컨테이너는 @Configuartion이 붙은 AppConfig를 설정 정보로 사용한다.
-> Container를 호출하기 위해선 ApplicationContext, AnnotationConfigApplicationContext를 활용해야함.
여기서 @Bean 이라고 적한 메서드를 모두 호출하여 반환된 객체를 스프링 컨테이너에 등록한다.
-> 이를 스프링 빈이라고 한다. 메소드 이름이 스프링빈의 이름이다.
3) 이전에는 개발자가 필요한 객체를 AppConfig를 통해 직접 조회했으나, 이제는 스프링 컨테이너를 통해 필요한 스프링 빈을 찾아야 한다. 스프링빈은 AC.getBean() 메소드를 통해 찾을 수 있다.
-> 코드가 오히려 복잡해진 것 같은데, 이게 어떤 장점이 있을까? : 이를 다음 시간부터 살펴보기로 함.
+) 참고 포스팅
https://velog.io/@gillog/Spring-DIDependency-Injection
#위 포스팅은 인프런 김영한 팀장님의 스프링 핵심 기본편을 수강한 내용을 정리하였습니다.
'Web > Java (Spring+JSP)' 카테고리의 다른 글
Spring 핵심 원리 #7- 스프링 컨테이너 관련 인터페이스 (0) | 2022.01.11 |
---|---|
Spring 핵심 원리 #6- 스프링 컨테이너 생성과 등록된 빈 조회 (0) | 2022.01.07 |
Spring 핵심 원리 #4- AppConfig 리팩토링/총정리 (0) | 2021.11.12 |
Spring 핵심 원리 #3- 새로운 할인 정책/AppConfig 적용 (0) | 2021.11.12 |
Spring 핵심 원리 #2- 주문/할인 도메인 개발 (0) | 2021.11.10 |