티스토리 뷰

반응형

Spring을 처음 배웠을때 Service, Dao를 Autowired로 필드 주입으로 배웠습니다.

당연히 지금까지 필드 주입으로 해야 한다고 생각 했습니다.

얼마전까지 node로 서버를 개발하다 다시 Spring을 사용해야 할때까지 말이죠.

 

하지만 최근에 Spring Boot 문서를 보다보니 Autowired를 필드 주입이 아닌 생성자 주입으로 권고 하고 있는 것을 알았습니다.

왜 필드 주입을 하는지 그리고 공식 문서에서 어떤 방식은 추천하는지 알아 보겠습니다.

 

1. Autowired 생성자 주입으로 변경하는 방법.

 

우리가 배워 왔던 방식은 아래와 같은 코드 입니다.

public  class  ExampleCase{
 
    @Autowired
    private  ChocolateService  chocolateService;
 
    @Autowired
    private  DrinkService  drinkService;
}

선언하고자 하는 Service, Component에 바로 @Autowired를 선언하여 필드 주입으로 사용합니다.하지만 Spring Boot 공식 문서에는 필드 주입이 아닌 생성자 주입으로 안내하고 있습니다. 그렇다면 생서자 주입으로 변경하려면 어떻게 해야 할까요?

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

필드 주입 했던 요소들을 생성자에 선언해주고 생성자에 @Autowired를 선언하면 됩니다. 필드 주입일때는 선언하지 못했던 final을 선언해주어 혹시 모를 Service, Component의 변경을 방지 합니다. 또한 생성자 주입을 사용할때는 @Autowired 어노테이션을 선언하지 않아도 주입이 되기 때문에 아래와 같이 변경이 가능합니다.

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

@Autowired 선언을 하지 않기 때문에 코드가 조금 갈끔해지고 import에도 사라지게되죠. 작지만 코드 2줄을 없앨 수 있겠네요. 여기서 프로젝트에서 Lombok 라이브러리를 사용한다면 더욱 깔끔하게 변경이 가능합니다.

@RequiredArgsConstructor
public  class  ExampleCase{
    private  final  ChocolateService  chocolateService;
    private  final  DrinkService  drinkService;
}

Lombok에서 제공하는 @RequiredArgsConstructor 어노테이션을 사용하면 생성자를 따로 만들지 않아도 됩니다. @RequiredArgsConstructor 어노테이션은 final로 선언되지 않은 변수와 @NonNull 어노테이션을 선언한 변수에 대해 생성자를 만들기 때문에 우리가 위에서 보았던 생성자와 동일하게 만들어 주죠. 그렇기 때문에 Lombok 라이브러리를 사용할때는 꼭 final를 붙여주어야 생성자 주입이 됩니다. 이점 꼭 주의해서 코드를 줄여보세요.

2. 필드주입이 아닌 생성자 주입을 사용하는 이유?

필드 주입이 아닌 생성자 주입을 사용하는 이유는 다음과 같습니다.

2-1 순환 의존성 확인

필드 주입으로 순환 의존성을 파악하기는 어렵습니다. 생성자 주입을 하게 되면 서버 기동시 순환 의존성을 가지는 요소들을 파악할 수 있게 에러 메세지를 표시 하면서 서버 기동이 되지 않습니다. 

2-2 불변성

필드 주입은 final를 선언할 수 없지만 생성자 주입은 final를 선언함으로써 객체가 변하지 않도록 방지해줍니다.

2-3 단일 책임 원칙 위반 확인

Lombok을 사용하지 않았을때 필드 주입을 하게 되면 코드량이 상당히 많아지고 생성자를 확인하여 얼마나 많은 요소들을 사용하지는 한눈에 파악이 가능합니다. "클래스는 한 개의 책임을 가진다" 단일 책임 원칙 위반을 생각해 볼 수 있게 해줍니다. 이로서 클래스를 리펙토링 하거나 클래스를 분리하는 데 도움이 될 수 있습니다.

 

참고 자료 

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-spring-beans-and-dependency-injection

반응형
댓글