Field Injection(필드 주입)

변수 선언부에 @Autowired Annotation을 붙인다.

@Component
public class SampleController {
    @Autowired
    private SampleService sampleService;
}

 

필드주입을 사용하면 안되는 이유

1. 단일 책임(SRP)의 원칙 위반 

의존성을 주입하기가 쉽다.
@Autowired 선언 아래 개수 제한 없이 무한정 추가할 수 있다. Constructor의 parameter가 많아짐과 동시에 하나의 Class가 많은 책임을 떠안는다는 걸 알게된다.

 

2. 의존성이 숨는다. 

DI Container를 사용한다는 것은 Class가 자신의 의존성만 책임진다는게 아니라 제공된 의존성 또한 책임진다. 그래서 Class가 어떤 의존성을 책임지지 않을 때, 메서드나 생성자를 통해(Setter나 Constructor) 확실히 커뮤니케이션이 되어야한다.

하지만 Field Injection은 숨은 의존성만 제공해준다.

 

3. DI container의 결합성과 테스트 용이성

DI Framework의 핵심 아이디어는 관리되는 Class가 DI Container에 의존성이 없어야 한다.

DI Container 없이도 Unit Test에서 Instance화 시킬 수 있고, 각각 나누어서 테스트도 할 수 있다. Container의 결합성이 없다면 관리하거나 관리하지 않는 Class를 사용할 수 있고, 심지어 다른 DI Container로 전환할 수 있다.

하지만, Field Injection을 사용하면 필요한 의존성을 가진 Class를 곧바로 Instance화 시킬 수 없다.

 

4. 불변성

Constructor Injection과 다르게 Field Injection은 final을 선언할 수 없다. 그래서 객체가 변할 수 있다.

 

5. 순환 의존성

Constructor Injection에서 순환 의존성을 가질 경우 BeanCurrentlyCreationExeption을 발생시킴으로써 순환 의존성을 알 수 있다. 

그러나 Field Injection은 스프링 컨테이너 말고는 외부에서 주입할 수 있는 방법이 없다.

순환 의존성?
A Class가 B Class를 참조하는데 B Class가 다시 A Class를 참조할 경우,A Class가 B Class를 참조하고, B Class가 C Class를 참조하고 C Class가 A Class를 참조하는 경우 이를 순환 의존성(Circular Dependency)이라고 부른다.

 

읽기 쉽고 사용이 편하단것 이외엔 장점이...

 

 

 

Setter Injection(수정자 주입)

Setter Injection 선택적인 의존성을 사용할 때 유용하다. 상황에 따라 의존성 주입이 가능하다.

//Setter Injection은 set Method를 정의해서 사용한다.
@Component
public class SampleController {
    private SampleService sampleService;
 
    @Autowired
    public void setSampleService(SampleService sampleService) {
        this.sampleService = sampleService;
    }
}

Setter Injection으로 의존관계 주입은 런타임시에 할 수 있도록 낮은 결합도를 가지게 구현되었다.

 

하지만 Setter Injection을 통해서 Service의 구현체를 주입해주지 않아도 Controller 객체는 생성이 가능하다.

Controller 객체가 생성가능하다는 것은 내부에 있는 Service의 method 호출이 가능하다는 것인데, set을 통해 Service의 구현체를 주입해주지 않았으므로, NullPointerException 이 발생한다.

 

주입이 필요한 객체가 주입이 되지 않아도 얼마든지 객체를 생성할 수 있다는 것이 문제다.

 

이를 해결할 아이가 Constructor Injection이다

 

 

 

 

Constructor Injection(생성자 주입)

//Constructor에 @Autowired Annotation을 붙여 의존성을 주입받을 수 있다.
@Component
public class SampleService {
    private SampleDAO sampleDAO;
 
    @Autowired
    public SampleService(SampleDAO sampleDAO) {
        this.sampleDAO = sampleDAO;
    }
}

@Component
public class SampleController {

	private final SampleService sampleService = new SampleService(new SampleDAO());
    
	...
}

 

생성자 주입을 사용해야하는 이유!!!

(Spring Framework Reference에서 권장하는 방법은 생성자를 통한 주입~!)

생성자를 사용하는 방법이 좋은 이유는 필수적으로 사용해야하는 의존성 없이는 Instance를 만들지 못하도록 강제할 수 있기 때문이다.

 

Spring 4.3버전부터는 Class를 완벽하게 DI Framework로부터 분리할 수 있다.

 

단일 생성자에 한해 @Autowired를 붙이지 않아도 된다.

 

또한 앞서 살펴본 Field Injection의 단점들을 장점으로 가져갈 수 있다.

  • null을 주입하지 않는 한 NullPointerException 은 발생하지 않는다.
  • final 을 사용할 수 있다.
  • 순환 의존성을 알 수 있다.
  • 의존성을 주입하기가 번거로워 위기감을 느낄 수 있다. (이를 바탕으로 SRP원칙을 생각하게 되고 리팩토링하게된다.)

Reference.

link1

출처 : https://sehun-kim.github.io/sehun/springbean-lifecycle/#2

 

스프링의 삼각형
DI IoC AOP

스프링의 기반이 되는 설계 개념인 스프링의 삼각형

 

 

의존성 주입 DI ( Dependency Injection )

Inversion of Control 이라고도 하는 의존 관계 주입(Dependency Injection)이라고도 하며, 어떤 객체가 사용하는 의존 객체를 직접 만들어 사용하는게 아니라, 주입 받아 사용하는 방법이다. (new 연산자를 이용해서 객체를 생성하는 것이라고 생각하면 된다) 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능으로, DI(의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다.

출처 :https://velog.io/@gillog/Spring-DIDependency-Injection

A 객체에서 B, C객체를 사용(의존)할 때, A 객체에서 직접 생성 하는 것이 아니라 외부(IOC컨테이너)에서 생성된 B, C객체를 조립(주입)시켜 setter 혹은 생성자를 통해 사용하는 방식 

 

예시로 장난감과 배터리를 들 수 있다. 장난감들은 베터리가 있어야 움직일 수 있으며 즉 베터리에 의존하고 있다. 장난감들에게 베터리를 넣어주는 것을 의존성 주입이라고 생각하면 좋다.

베터리의 일체형인 경우에는 생성자에서만 의존성을 주입해주는 상황이라 베터리가 떨어지게 된다면 다른 베터리로 교체하지 못하고 새로운 것으로 바꿔야 하기 때문에 유연하지 못한 방식이다. 

자바와 같은 경우엔 setter, 생성자를 이용해서 외부에서 주입해주는 상황은 외부에서 베터리를 교체해줄 수 있기 때문에 일체형보다 유연한 상황이다. 

 

 

출처 : https://velog.io/@gillog/Spring-DIDependency-Injection

스프링에서는 객체를 Bean이라고 부르며, 프로젝트가 실행될때 사용자가 Bean으로 관리하는 객체들의 생성과 소멸에 관련된 작업을 자동적으로 수행해주는데 객체가 생성되는 곳을 스프링에서는 Bean 컨테이너라고 부른다.

 

 

 

의존성 주입을 사용하는 이유

1. 재사용성을 높여준다.

2. 테스트에 용이하다.

3. 코드를 단순화 시켜준다.

4. 사용하는 이유를 파악하기 수월하고 코드가 읽기 쉬워지는 점이 있다.

5. 종속성이 감소하기 때문에 변경에 민감하지 않다.

6. 결합도(coupling)는 낮추면서 유연성과 확장성은 향상 시킬 수 있다.

7. 객체간의 의존관계를 설정할 수 있다.

 


Reference.

link1 link2

'🔥 > Spring' 카테고리의 다른 글

[spring] 빈 라이프 사이클과 범위  (0) 2021.08.31
[spring] 컴포넌트 스캔이란  (0) 2021.08.31
[Spring] "회초리단" 스프링 스터디 1차  (0) 2021.08.20
[Spring] DI의 세가지 방법  (0) 2021.08.18

+ Recent posts