본문 바로가기

web +a

스프링&웹 | 스프링 DI (+ 계획 변경..!! ㅠㅅ ㅠ)

스프링의 코어는 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 컨테이너를 이용하기 위해서 인터페이스 기반으로 부품화해야 한다!

스프링4입문, 한빛미디어, 80p

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월은 끝났다 🤔

반응형
다른 블로그