DI(Dependency Injection)
스프링이 다른 프레임워크와 차별화되어 제공하는 의존관계 주입 기능으로, 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다. 객체 자체가 아니라 Framework에 의해 객체의 의존성이 주입되는 설계 패턴. DI를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다.
- Framework에 의해 동적으로 주입되므로 여러 객체간의 결합이 줄어든다.
- Dependency Injection은 Spring Framework에서 지원하는 IoC의 형태
- 설정에 명시된대로 Container가
- 1) bean 객체를 생성하고
- 2) 종속된 주입을 수행한다.
- Dependency Injection(의존성 주입)과 Inversion Of Control(제어의 역전)은 같은 의미로 사용된다.
- IoC는 DI를 통해 달성된다.
- IoC(제어의 역전) : 프로그램 제어권을 framework가 가져가는것
- 개발자가 모든 제어의 중심이지만 코드 전체에 대한 제어는 framework가 한다.
- 개발자가 설정(xml, annotation 등)만 하면 Container가 알아서 처리한다.
- 즉, 우리는 Framework 속에서 프로그래밍을 하는 것
의존성 주입 방법(세 가지)
1. Contructor Injection
- 생성자를 통한 전달
2. Method(Setter) Injection
- setter()를 통한 전달
3. Field Injection
- 멤버 변수를 통한 전달
개발자가 할 일
- 주입할 것에 대한 Class를 작성(Tv, Person, ...)하는 것
- 어떤 것을 주입할 것인지 결정할 설정 파일(xml, annotation 등)을 작성하는 것
- 즉, 코드 상에는 전혀 변화가 없다.
※ 의존성이란?
Tv클래스는 selectRemco()메소드를 실행할 때에 getInfo()를 위해서 Machine클래스가 필요하다. 이럴 때 Tv 클래스가 Machine클래스에 의존성을 가지고 있다.(의존하고 있다)고 한다. 그렇다면 의존성이 왜 안 좋은 것일까?
의존성의 문제점
1. Unit Test가 어려워진다.
- 내부에서 직접 생성하는 객체에 대해서, 객체에 대해서 mocking을 할 방법이 없다. 그래서 단위 테스르를 하기가 까다로워진다.
ko.wikipedia.org/wiki/%EB%AA%A8%EC%9D%98_%EA%B0%9D%EC%B2%B4
medium.com/@SlackBeck/mock-object%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-85159754b2ac
2. Code의 변경이 어려워진다.
- Tv 클래스는 생성자에서 Machine객체를 직접 생성하여 사용하고 있다. 만약 나중에 Machine클래스가 Old Machine(오래된 기계) 등으로 바뀐다면 지금처럼 Machine클래스에 의존하고 있는 Tc 클래스도 같이 변경을 해주어야 한다. 즉, 객체간의 강한 결합력이 생긴다. 소프트웨어의 모듈화의 목적인 낮은 결합력과 높은 응집도에 해가 되는 행위이다.
Spring Container
Spring Framewor의 핵심 컴포넌드
- Container는 DI를 사용하여 응용 프로그램을 구성하는 bean 객체를 관리한다.
역할
bean을 포함하고 관리하는 책임이 있다.
1. 객체(bean)를 생성하고
2. 객체들을 함께 묶고
3. 객체들을 구성하고
4. 객체들의 전체 수명주기(lifecycle)를 관리
설정방법
Spring Container metadata 설정 방법(세 가지)
1. XML
- 1) 빈 객체 정의(Bean Definition)
- 2) 의존성 주입(Dependency Injection)
2. Java Annotation
3. Java Code
유형
- Spring Container의 2가지 유형
- 스프링 프레임워크를 초기화하는 역할을 한다
- 1) 스프링 컨테이너 생성
- 2) Bean들이 들어있는 XML 파일이 읽힘
- 3) XML 파일에 등록된 Bean들의 Life Cycle과 Dependency가 관리되기 시작
- 이런 컨테이너를 초기화시키기 위한 클래스는 다음과 같다.
1) XmlBeanFactory : Resource 객체를 사용해 컨텍스트 정의 파일을 로딩하는 단순한 BeanFactory
2) ClassPathXmlApplicationContext : 클래스 경로로부터 컨텍스트 정의 파일을 로딩하는 ApplicationContext
3) FileSystemXmlApplicationContext : 파일 시스템으로부터 컨텍스트 정의 파일을 로딩하는 ApplicationContext
4) XmlWebApplicationContext : 웹 어플리케이션 컨텍스트로부터 컨텍스트 정의 파일을 로딩하는 ApplicationContext
1. BeanFactory
- 주로 단순한 DI에서만 사용한다.
- XMLBeanFactory
2. ApplicationContext
- Resources가 제한되어 있지 않은 모든 곳에 사용한다.
- ClassPathXmlApplicationContext
- 프로퍼티 파일의 텍스트 메세지를 해석하는 능력이나 어플리케이션 이벤트를 관련된 이벤트 리스너에 발행하는 능력등과 같은 어플리케이션 프레임워크 서비스를 제공하는 BeanFactory의 개념위에 구현된 컨테이너
/* main함수에서 Contaier를 생성 */
// 설정 파일은 인자로 넣고, 해당 설정 파일에 맞게 bean들을 만든다.
ApplicationContext context =
new ClassPathXmlApplicationContext("spring/di/beans/bean.xml");
// getBean()을 통해 bean의 주소값을 가져온다.
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
※ BeanFactory, ApplicationContext의 차이
- BeanFactory가 Bean 생성 및 LifeCycle을 관리한다면, ApplicationContext는 Bean관리 뿐만 아니라 리소스 로딩, 이벤트 발행, 다국어 등 추가적인 기능을 갖고있다.
- ApplicationContext는 Pre-loadind(즉시 인스턴스 생성), BeanFactory는 lazy-loading(실제 요청받는 시점에서 인스턴스 생성)한다.
- 특별한 이유가 없다면 BeanFactory 보다는 ApplicationContext를 써야한다. 여기서 특별한이란 메모리 소비가 중요하거나 리소스가 제한된 장치들을 말한다. 일반적인 엔터프라이즈 어플리케이션은 ApplicationContext를 사용하는 게 낫다. 그 이유는 BeanPostProcessor 확장 포인트를 사용 할 수도 있고, 트랜잭션과 AOP와 같은 상당한 양의 지원을 받을 수 있다고 한다.
출처
'Web > 기초' 카테고리의 다른 글
[WEB기초] 싱글톤 패턴(Singleton Pattern) (0) | 2021.08.06 |
---|---|
[WEB기초] Spring 생성자 주입을 써야하는 이유 (0) | 2021.08.03 |
[WEB기초] web.xml (0) | 2021.01.10 |
[WEB기초] Servlet이란 (0) | 2021.01.10 |
[WEB기초] 로드 밸런서(Load Balancer) (0) | 2020.12.27 |