Back/Spring Java

Spring 필드주입(@Autowired)보다 생성자주입을 권장하는 이유

밍꿔 2020. 5. 25. 10:22


반응형

 

생성자주입을 권장하는 이유를 알아보기 앞서 스프링 프레임워크의 DI(Dependency Injection) 의존성 주입

 

방법은 크게 세가지로 볼 수 있다.

 

1. 필드주입

사용법이 매우 간단하다. 필드에 @Autowired 어노테이션을 붙여주면 자동으로 의존성이 주입된다.

 

편리하기 때문에 가장 많이 접할 수 있는 방법인 것 같다.

@Component
public class MadExample {

    @Autowired
    private HelloService helloService;
}

 

2. 수정자 주입

수정자(Setter)를 이용한 주입 방법도 있다. 다만 잘 사용하진 않은듯.

@Component
public class MadExample {

    private HelloService helloService;

    @Autowired
    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }
}

 

 

3. 생성자 주입

스프링 프레임워크 4.3 버전부터는 의존성 주입으로부터 클래스를 완벽하게 분리할 수 있다.

 

단일 생성자인 경우에는 @Autowired 어노테이션 조차 붙이지 않아도 되지만 생성자가 2개 이상인 경우에

 

는 생성자에 어노테이션을 붙여주어야 한다.

 

 

1) 생성자가 1개 인 경우

@Component
public class MadExample {

    // final로 선언할 수 있는 보너스
    private final HelloService helloService;

    // 단일 생성자인 경우는 추가적인 어노테이션이 필요 없다.
    public MadExample(HelloService helloService) {
        this.helloService = helloService;
    }
}

 

2) 생성자가 2개 이상인 경우

@Component
public  class  ExampleCase {
    
    private  final  ChocolateService  chocolateService;
    private  final  DrinkService  drinkService;
    
    @Autowired
    public ExampleCase(ChocolateService  chocolateService, DrinkService  drinkService) {
   	this.chocolateService = chocolateService;
   	this.drinkService = drinkService;
    }
}

 

3) @RequiredArgsConstructor를 사용하는 경우 (lombok설치 해야됨)

@Service
    @RequiredArgsConstructor
    public class BannerServiceImpl implements BannerService {
    
        private final BannerRepository bannerRepository;
    
        private final CommonFileUtils commonFileUtils;
        .
        .
        .

 

 

* 그렇다면 왜 생성자주입을 권장하는걸까?

 

 

1. 순환 의존성 (순환참조)

Constructor Injection과 다르게 Field Injection final을 선언할 수 없기때문에 객체가 변할 수 있다.

 

 

*순환 의존성

 

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

 

환 의존성을 알 수 있음.

 

 

*순환 의존성이란?


First Class가 Second Class를 참조하는데 Second Class가 다시 First Class를 참조할 경우 혹은 First Class가

 

Second Class를 참조하고, Second Class가 Third Class를 참조하고 Third Class가 First Class를 참조하는 경

 

우 이를 순환 의존성이라고 부릅니다. (순환 참조)

 

 

2.단일 책임의 원칙 위반

필드 주입 망식은 일단 의존성을 주입하기 쉽습니다. 

 

@Autowired 선언 아래 3개든 10개든 막 추가할 수 있으니 여기서 Constructor Injection을 사용하면

 

다른 Injection 타입에 비해 위기감 같은 걸 느끼게 해줍니다. 

 

Constructor의 파라미터가 많아짐과 동시에 하나의 클래스가 많은 책임을 떠안는다는 걸 알게됩니다.

 

이때 이러한 징조들이 리팩토링을 해야한다는 신호가 될 수 있습니다.

 

 

3.의존성이 숨는다.

DI(Dependency Injection) 컨테이너를 사용한다는 것은 클래스가 자신의 의존성만 책임진다는게 아닙니다.

 

제공된 의존성 또한 책임집니다.

 

그래서 클래스가 어떤 의존성을 책임지지 않을 때, 메서드나 생성자를 통해(Setter나 Contructor) 확실히

 

커뮤니케이션이 되어야만합니다. 하지만 Field Injection 숨은 의존성만 제공해줍니다.

 

 

4.DI 컨테이너의 결합성과 테스트 용이성

DI 프레임워크의 핵심 아이디어는 관리되는 클래스가 DI 컨테이너에 의존성이 없어야합니다.

 

즉, 필요한 의존성을 전달하면 독립적으로 인스턴스화 할 수 있는 단순 POJO여야합니다.

 

DI 컨테이너 없이도 유닛테스트에서 인스턴스화 시킬 수 있고, 각각 나누어서 테스트도 할 수 있습니다.

 

컨테이너의 결합성이 없다면 관리하거나 관리하지 않는 클래스를 사용할 수 있고,

 

심지어 다른 DI 컨테이너로 전환할 수 있습니다.

 

하지만, Field Injection을 사용하면 필요한 의존성을 가진 클래스를 곧바로 인스턴스화 시킬 수 없습니다.

 

 

 

 

 

https://madplay.github.io/post/why-constructor-injection-is-better-than-field-injection

 

 

반응형

'Back > Spring Java' 카테고리의 다른 글

특정일로 부터 날짜 계산 (Java)  (0) 2020.07.28
압축파일 생성  (0) 2020.07.03
@Async 비동기 호출  (0) 2020.04.27
for문(Loop) 성능 개선 - 2  (0) 2020.04.16
for문(Loop) 성능 개선 - 1  (0) 2020.04.13