본문 바로가기

spring

[Spring] 생성자 주입 VS 필드 주입 VS Setter 주입: 당신의 선택은?

[배경]

 의존성 주입은 소프트웨어 모듈 간의 결합도를 낮추고, 코드의 테스트와 유지보수를 쉽게 해주는 강력한 패턴입니다. 그러나 생성자 주입과 필드 주입 중 어느 것이 더 나은 선택인지 확신이 서지 않을 때가 많을 것입니다. 이 글에서는 각 주입 방식이 제공하는 이점과 잠재적인 단점을 설명하고, 여러분의 코딩 스타일과 프로젝트 요구사항에 맞는 최적의 선택을 도와드리겠습니다.

 


 

[내용]

1. 생성자 주입 방법

 생성자 주입은 의존성을 주입받는 클래스의 생성자를 통해 의존성을 주입하는 방법입니다. 이 방법은 체가 생성될 때 의존성을 한번에 주입받기 때문에 의존성 주입 후에 변경이 불가능하다는 점에서 불변성을 확보할 수 있다는 장점이 있습니다.

 

(예시코드)

public class UserService {

    private final UserRepository userRepository;

    // 생성자를 통해 의존성 주입
    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

 

2. 필드 주입 (Field Injection)

 필드 주입은 의존성을 주입받는 클래스의 필드에 직접 의존성을 주입하는 방법입니다. 이 방법은 코드가 간결하다는 장점이 있지만, 의존성이 변경될 가능성이 있고 테스트하기 어렵다는 단점이 있습니다.

 

(예시코드)

public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

 

필드에 @Autowired 어노테이션만 붙여주면 자동으로 의존성 주입됩니다.사용법이 매우 간단하기 때문에 가장 많이 접할 수 있는 방법입니다.

 

3. 의존성 주입 장단점 비교

구분 생성자 주입   필드 주입
장점 의존성을 명시적으로 표시하여 코드 가독성 향상   설정이 간단하고 코드가 간결함
객체의 불변성 유지   프레임워크를 통한 간편한 의존성 주입 가능
단위 테스트 용이   간단한 프로젝트에서 사용하기 용이
순환 의존성 문제 방지    
       
단점 여러 의존성을 주입할 때 코드가 길어질 수 있음   객체의 불변성 유지 어려움
불필요한 의존성 주입 가능성   의존성을 한눈에 파악하기 어려움
    순수 자바로 테스트 시 어려움이 있음
    순환 의존성 문제가 발생할 수 있음

 

4. 생성자 주입을 권장하는 이유

 Spring Framwork reference에서 권장하는 방법은 생성자를 통한 주입입니다. @Autowired 어노테이션만으로 간단하게 의존성을 주입할 수 있는데 왜 생성자 주입 방법을 권장하는걸까요? 위에서 분석한 4가지의 장점 때문에 생성자 주입방식을 권장합니다. 상세히 설명하자면 다음과 같습니다. 

 

1) 의존성 명시성 : 생성자를 통해 의존성을 주입받기 때문에, 클래스의 생성자 시그니처만 보면 필요한 의존성을 쉽게 알 수 있습니다.
2) 불변성 유지 : 의존성을 final로 선언하여, 객체 생성 이후에 의존성이 변경되지 않도록 할 수 있습니다.
3) 단위 테스트 용이성 : 생성자를 통해 의존성을 주입받기 때문에, 단위 테스트 시 모킹(mocking)이나 스터빙(stubbing)이 쉽게 가능합니다.
4) 순환 의존성 : 의존성 주입 시점에서 순환 의존성을 쉽게 발견할 수 있습니다.

 

그러면 왜 이런 차이가 발생하나요???

 

그 이유는 바로 생성자 주입 방식은 필드 주입과는 빈을 주입하는 순서가 다릅니다.

필드 주입먼저 빈을 생성한 후, 주입하려는 빈을 찾아 주입합니다.
하지만, 생성자 주입은 먼저 생성자의 인자에 사용되는 빈을 찾거나 빈 팩토리에서 만듭니다.
그 후에 찾은 인자 빈으로 주입하려는 빈의 생성자를 호출합니다.
즉, 먼저 빈을 생성하지 않고 주입하려는 빈을 먼저 찾습니다.
따라서 생성자 주입 방식을 사용하면 순환 참조가 발생하면서 오류가 검출 됩니다.
객체 생성 시점에 빈을 주입하기 때문에 서로 참조하는 객체가 생성되지 않은 상태에서 그 빈을 참조하기 때문에 오류가 발생합니다. 사전에 순환 참조를 방지하기 위해서는 생성자 주입을 사용하는 것이 좋습니다.

 

 

5. Setter 주입

 객체의 의존성을 설정자 메서드(Setter method)를 통해 주입하는 방식입니다. 이 방법은 객체 생성 이후에 의존성을 설정할 수 있는 유연성을 제공합니다. Setter 주입의 특징으로는 유연성, 선택적 의존성 주입, 단일 책임 원칙(SRP) 준수, 의존성 순환 문제 해결등이 있습니다. Setter 메서드를 사용하여 필요한 의존성을 주입할 수 있습니다. 이를 통해 객체가 생성된 이후에도 의존성을 변경하거나 추가할 수 있습니다. 그리고 생성자 주입과 달리 Setter 주입은 모든 의존성을 필수로 제공하지 않아도 됩니다. 즉, 특정 의존성은 필요할 때만 주입될 수 있습니다.
생성자 주입의 경우 객체의 생성과 의존성 주입이 결합되지만, Setter 주입에서는 의존성 설정이 별도의 메서드로 분리되어 더 명확한 구조를 가질 수 있습니다.
의존성 순환 문제 해결로 생성자 주입에서는 순환 의존성 문제(circular dependency)가 발생할 수 있습니다. Setter 주입을 사용하면 객체가 생성된 후 의존성을 설정하므로, 이 문제를 피할 수 있습니다.

 

하지만 단점으로는 다음과 같습니다.

 

  • 객체 일관성 저하: Setter 주입 방식에서는 객체가 완전히 초기화되기 전에 사용될 가능성이 있습니다. 이는 객체의 일관성을 저하시킬 수 있으며, 사용자가 객체를 사용할 때 모든 의존성이 올바르게 설정되었는지 확인하는 추가적인 코드가 필요할 수 있습니다.
  • 가독성 저하: 생성자 주입 방식에 비해 어떤 의존성이 필수인지 명확하지 않을 수 있으며, 코드의 가독성이 떨어질 수 있습니다.
  • 불변성 감소: Setter 주입은 객체의 상태를 변경할 수 있게 하므로, 객체의 불변성을 유지하기 어렵습니다.

 


[결론]

 의존성 주입의 올바른 선택은 코드의 품질을 좌우합니다. 생성자 주입과 필드 주입을 비교해보았을 때, 명확하고 안전한 생성자 주입이 더 많은 장점을 제공합니다. 주니어 개발자로서, 이제 생성자 주입을 통해 더욱 견고하고 유지보수하기 쉬운 코드를 작성해 나가세요. 여러분의 코드는 더 높은 품질을 향해 나아갈 것입니다.

 


[출처 및 참조]