스프링의 코어는 DIxAOP 컨테이너이고, DI는 스프링 코어의 하나이다.
DI 의미
dependancy injection
: 객체를 직접 생성하는 것이 아닌, 외부에서 생성하여 주입시켜주는 방식이다.
: 예를들면 new로 직접생성하지 않고, 외부에서 생성된 객체를 setter(), 생성자를 통해 사용하는 방식이다.
: 스프링의 DI 컨테이너에서 객체를 생성하고, 필요한 곳에 객체를 주입시킬 수 있다.
∨ 의존 관계 주입?
: 오브젝트 사이의 의존관계를 만드는 것임
: 어떤 오브젝트가 의존(이용)할 오브젝트를 주입(injection, 프로퍼티(인스턴스변수)에 설정)한다는 것임
∨ 인터페이스를 이용해 부품화를 실현하는 것
: 인터페이스와 DI 컨테이너를 이용하여 제대로 '부품화'할 수 있다.
ex)
Product (let VO), ProductSampleRun, ProductService, ProductDao가 있다고 하자.
DI 컨테이너를 사용하지 않는다면 (그리고 팩토리 메서드로 구현하지 않았다고 하면)
- ProductSampleRun에서 new ProductService하고
- ProductService에서 new ProductDao해서 각 인스턴스를 이용하는 형태일 것이다.
반면 DI 컨테이너를 사용하면
- 그러한 인스턴스는 DI컨테이너가 생성해준다.
- 즉 클래스에서 new연산자가 사라지게 해준다
=> 팩토리 메서드를 구사하지 않아도 DI 컨테이너가 건네는 인스턴스를 인터페이스로 받아서, 인터페이스 기반 컴포넌트화(부품화)를 구현가능케 한다.
- 인젝션(의존관계주입)까지 해준다.
ex)
위 상황을 도표로 나타내면 다음과 같다
DI컨테이너를 이용하고 있고, 인터페이스(ProductService, ProductDao)와 구현클래스(~~Impl)을 두었다.
이렇게 DI 컨테이너를 이용하기 위해서 인터페이스 기반으로 부품화해야 한다!
DI컨테이너의 구현클래스 인스턴스화는 디폴트 1회만 실행한다.
=> 굳이 Singleton으로 구현하지 않아도 DI가 Singleton을 실현해준다.
ex)
위 상황의 시퀀스를 81page에서 확인할 수 있다.
(main()가동하여 execute() 호출되면 DI컨테이너가 생성되고 각 인터페이스를 취득하게 되는.. 그러한 과정에 대한 내용임)
DI를 어떻게 이용할 것인가? (아직 이해안감)
DB에서 값을 가져와 인스턴스화하는 작업에는 어울리지 않는다
ㄴ 고정된 값을 가진(like 파일, Valued Object) 인스턴스를 생성할 때 잘 사용됨
(아직 이해안감↓)
(좋은 예) 컨트롤러-서비스, 서비스-DAO 의존관계 구축
(나쁜 예) 서비스-도메인, DAO-도메인
스프링이 DI컨테이너를 이용하여 DI하는 방법
- 어노테이션을 이용한 DI
ㄴ매우 편리하여 소규모 개발에 자주 사용되지만 대규모에선 관리가 쉽지 않다
- Bean 정의 파일을 이용한 DI
ㄴ대규모 개발에서 DI를 관리하는 방법이다. 어노테이션과 겸용도 자주 함.
- JavaConfig를 이용한 DI
ㄴ호불호 갈린다. 혼자 프로그래밍하는 경우 편리하다고 한다.
※ 어떤 방식이든 트랜잭션 관리는 문제가 되며, 신경써야 한다.
어노테이션을 이용한 DI
DI할때 사용하는 어노테이션의 기능 중심으로 설명한다.
∨ @Autowired와 @Component
ㄴ 인젝션(의존관계)을 받기 위한 설정이다.
ㄴ DI 컨테이너가 관리한다.
ⓐ 인스턴스 변수 (혹은 메서드)앞에 @Autowired를 붙이면
ⓑ DI컨테이너가 그 인스턴스 변수 타입에 대입할 수 있는 클래스를 찾아낸다.
@Component가 붙은 클래스 중에서 찾아낸다 + Bean 정의에서 클래스 스캔 범위 설정 필요
ⓒ 그 클래스의 인스턴스를 인젝션해준다.
- 이때, 변수는 private이어도 상관 없다 & setter도 필요가 없다
- @Component가 붙은 클래스가 여러 개 있어도, @Autowired 인스턴스 변수와 형이 다르면 인젝션되지 않는다.
cf. 타입을 보고 인젝션 하는 방법 : byType
cf. 기본적으로 인젝션 가능한 클래스 타입은 하나여야 한다! (에러 발생)
=> BUT 그럴경우, 구현클래스를 테스트용 클래스로 바꾸고 싶을 때 불편하다.
=> 회피하는 세가지 방법이 존재한다. (92p)
① 디폴트 Bean을 설정하는 @Primary를 @Bean이나 @Component에 부여하기
② @Autowired와 병행하여 @Qualifier하기 (+Component에도 이름 지정)
: 이름을 보고 인젝션하는 방법 : byName
③ Bean 정의파일인 context:component-scan을 잘 이용하기
ex)
let : ProductServiceImpl과 ProductDaoImpl에 @Component를 붙여놓음
then : @Autowired를 붙인 어떤 인스턴스 변수 private ProductDao productDao에는 대입가능한 타입의 클래스를 @Component 붙인 클래스중에서 찾아 인젝션해준다.
위와 같이 어노테이션으로 DI를 구현하기 위해 Bean 정의 파일(XML로 기술됨) 또한 필요하다.
Bean 정의 파일 이름 관습 : applicationContext.xml
해당 파일에는 beans 태그, 그리고 bean과 context 속성(xml의 스키마) 등이 사용된다.
주요 스키마들과 태그는 86, 87 page에 있는데 여기 정리하지는 않겠다.
cf) @Component 확장 어노테이션을 이용할 수도 있다.
예를들면 ProductServiceInpl 클래스에서는 @Component 대신 @Service를 사용한다든가,
ProductDaoImpl 클래스에서는 대신 @Repository로 바꾼다든가..
작전변경... 흡
이 책으로 먼저 세세히 하는 것보다..
강의 따라하면서 맥락 잡아가는게 더 나은 선택이라고 느낀다.
요 책도 되게 괜찮긴 한데 이해하는 속도좀 내야할 것 같아서..
++ 부차적인 것인지 아닌지가 구분이 잘 안가는 게 문제
아무래도 다들 Spring하면 강추하는 김영한선생님 강의를 먼저 듣는게 나을 것 같다.
그 강의.. 어차피 언젠가는 들을 계획이었던거.. 여름방학때 들어버려야쥐.....
이휴... 시간 잘 써야겠다~~~ 벌써 6월은 끝났다 🤔
'web +a' 카테고리의 다른 글
DIP, OCP 원칙이 깨지는 문제를 Spring으로 해결 (0) | 2022.07.04 |
---|---|
기본&중요 | SOLID 그리고 스프링 (0) | 2022.07.04 |
스프링&웹 | 각 레이어에 관련된 스프링 기능 (0) | 2022.06.29 |
스프링&웹 | 웹애플리케이션의 문제점 & 스프링의 해결 (0) | 2022.06.29 |
스프링&웹 | 기초 지식 2 - 레이어별 책임 (0) | 2022.06.28 |