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

+ Recent posts