IoC(Inversion of Control, 제어의 역전)
- 제어의 흐름이 역전되는 것.
객체가 자신이 사용할 객체를 스스로 선택하지 않고, 스스로 생성하지도 않음.
- 제어의 권한이 객체 자신에게 없고 프레임워크에 있게 됨.
- 라이브러리를 사용하는 어플리케이션 코드는 어플리케이션 코드를 직접 제어하지만, 프레임워크는 거꾸로 어플리케이션 코드가 프레임워크에 의해 사용됨.
프레임워크가 흐름을 주도하며, 개발자가 만든 어플리케이션 코드를 사용하는 것.
- 즉, 어플리케이션 코드가 프레임워크가 짜놓은 틀에서 수동적으로 동작하게 됨. 이를 Hollywood Principle 이라고도 부름.
IOC 컨테이너
- IOC를 가능하게 하는 공간.
- 객체(인스턴스) 생성과 파괴에 이르는 생명주기를 대신 처리.
- 클래스 생성 시 생성에 대해 필요한 의존관계를 맺어주고 개별 객체들의 의존관계 설정 역시 처리함.
- 의존도와 결합도를 낮춰줌.
DDD(Domain Driven Design, 도메인 중심으로 설계하는 방법)
- Domain
어플리케이션 내 로직들이 관여하는 정보와 활동의 영역.
ex) 특정 서비스에서 일어나는 일들은 '회원'과 관련된 작업. 여기서 회원이 도메인.
- DDD에서는 Entity마다 Repository를 만드는 경우가 많은데, 여러 Entity를 묶어 하나처럼 사용하는 경우가 많음. 이러한 연관 객체 묶음을 Aggregate라 하고, 그 안의 특정 Entity를 Aggregate Root라고 함.
- Aggregate : Entity의 집합.
Aggregate Root는 하나의 Entity. 이런 Entity의 집합이 Aggregate가 됨.
DDD와 Aggregate
- Order Aggregate를 단위로 Transaction이 보장되어야 함.
- OrderRepository를 통해서 Order을 Database에 저장한다.
- Repository는 Entity를 저장하는 저장소.
ApplicationContext
스프링 컨테이너
참고 블로그
- IOC Container에서는 개별 객체들의 의존관계 설정이 자동으로 이루어지고 객체들의 생성과 파괴, 조합 등을 관장.
- 클래스의 사용을 Regist 하면 필요한 의존관계를 맺어주고 생명주기를 관리하면서 객체에 대한 인스턴스를 만들어줌.
- 이런 IOC Container을 스프링에서는 ApplicationContext라는 인터페이스를 통해서 제공.
- ApplicationContext는 BeanFactory를 상속하는데(하위 인터페이스) 객체에 대한 생성, 조합, 의존관계설정 등을 제어하는 IOC 기본기능을 BeanFactory가 담당.
- BeanFactory : 스프링 컨테이너의 최상위 인터페이스. 스프링 빈을 관리, 조회하는 역할을 함.
- Bean : 스프링에서 제공하는 ApplicationContext, BeanFactory, IOC Container에 의해 관리되는 객체를 말함.
IOC에서 관리되는 객체와 아닌 객체를 분리하기 위해서 만든 용어.
- 스프링의 ApplicationContext는 Configuration Metadata를 통해 Bean을 등록.
- Configuration Metadata을 이용, IOC Container에서 관리되는 객체들을 생성.
- Application의 객체들을 도식화.
- xml, 자바 파일 기반으로 작성 가능
xml : GenericXmlApplicationContext 기반.
Java : AnnotationConfigApplicationContext 기반.
- 클래스에 @Configuration, 각 메서드에 @Bean를 붙여 설정클래스로 변환 가능.
일반 클래스가 아닌, Bean을 정의한 Configuration Metadata로 선언해줄 수 있음.
DI(Dependency Injection, 의존관계 주입)
- IOC를 구현하는 하나의 패턴. (IOC는 전략 / 서비스 로케이터 / 팩토리/ 의존관계 주입 패턴을 통해서 구현할 수 있음.)
- 의존관계를 외부에서 결정하고 주입하는 것.
- 다음의 세가지 조건을 충족해야 함.
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야 한다.
- 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
- 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.
- 생성자를 통해 객체를 주입받는 패턴을 생성자 주입 패턴이라고 함.
Constructor-based Dependency Injection
- DI의 장점.
1 의존성이 줄어듬 : 의존도가 높으면 의존대상이 변화에 따라 수정해주어야 하지만, DI로 구현하면 주입받는 대상이 변하더라도 구현 자체를 수정하지 않아도 되거나, 수정 사항이 줄어들게 됨.
2 재사용성이 높은 코드가 됨 : 다른 클래스에서 재사용할 수 있다.
3 테스트하기 좋은 코드가 됨
4 가독성이 높아짐 : 기능들을 별도로 분리, 가동성이 높아짐.
참고
Circular dependencies
- A -> B를 참조하고 B -> A를 참조할 경우 순환 의존관계가 형성되면서 예외가 발생할 수 있다.
- 서로가 서로를 참조하기 때문에 무한루프에 빠져버린다. A에 B가 필요하고, B에 A가 필요한 경우니까.