본문 바로가기
일지

[Spring] 생성자 주입 : @Autowired(필드 주입) 대신 생성자 주입 권장 이유

by 닉닉눅 2023. 6. 16.
728x90
반응형

개인 프로젝트를 만들다가 @Autowired를 사용하여 의존성을 주입한 부분의 노란 전구를 발견했습니다.🤔

그냥 지나칠 수 없기에 한번 확인해보니 생성자를 사용하는 것을 저에게 권유하고 있습니다.

생성자 주입을 권장하는 스프링
생성자 주입을 권장하는 스프링

 

의존성 주입이란?

의존성 주입은 객체가 생성될 때 필요한 객체를 주입하는 것을 말합니다. 의존성 주입을 할 때는 필드 주입, 생성자 주입, setter 주입을 사용할 수 있습니다.

  • 필드 주입 : 객체의 필드에 의존성을 주입하는 방법입니다.
  • 생성자 주입 : 객체의 생성자에 의존성을 주입하는 방법입니다.
  • setter 주입 : 객체의 setter 메서드에 의존성을 주입하는 방법입니다.

 

예시


필드 주입

public class UserService {
    @Autowired
    private UserRepository userRepository;

    public void save(User user) {
        userRepository.save(user);
    }
}

 

생성자 주입

public class UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

public void save(User user) {
    userRepository.save(user);
}

 

setter 주입

public class UserService {
    private UserRepository userRepository;

    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void save(User user) {
        userRepository.save(user);
    }
}

 

생성자 주입 권장 이유


1. 생성자 주입 순환 참조를 방지합니다.

 

순환 참조는 객체 A가 객체 B를 참조하고, 객체 B가 객체 A를 참조하는 것을 말합니다. 순환 참조가 발생하면 객체를 생성할 수 없거나, 객체의 메서드를 호출할 수 없습니다.

생성자 주입으로 testservice와 madservice가 서로를 참조한다면 컴파일 단계에서 에러가 발생하여 사용자에 알려줍니다.

*순환 참조는 설계 단계의 문제이므로 다시 설계해야 합니다.*

Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  testService defined in file [~~~/TestService.class]
↑     ↓
|  madService defined in file [~~~/MadService.class]
└─────┘

 

2 .생성자 주입은 의존성이 주입되지 않은 상태에서 객체가 생성될 수 없기 때문에 필드 주입보다 안전합니다.

 

 

3. 생성자 주입은 코드가 깨끗하고 테스트하기 쉽습니다.

/*UserService 클래스는 UserRepository 클래스의 인스턴스를 생성자 주입으로 주입받습니다. 
UserService 클래스의 save() 메서드는 User 객체를 UserRepository 클래스에 저장합니다.*/

UserService userService = new UserService(new UserRepository());
userService.save(user);

 

4. 생성자 주입은 의존성의 결합도를 낮추는 데 도움이 됩니다.

 

 

5. 생성자 주입은 final을 사용할 수 있습니다

불변 객체나 null이 아님을 보장할 때 사용할 수 있으며, 다음은 TestRepository에 null을 참조하도록 변경하면 NullPointerException이 발생함을 보여주는 코드입니다.

@Service
public class TestService {
    private final TestRepository TestRepository;

    public TestService(TestRepository Testepository) {
        this.TestRepository = TestRepository;
    }

    public void someMethod() {
        //final을 사용함으로 NullPointerException이 발생
        TestRepository = null;
    }
}

final로 선언된 필드는 값을 변경할 수 없기 때문에 의존성 주입의 안전성을 높일 수 있습니다.

 

 

필드 주입은 간단하고 사용하기 쉽지만, 의존성이 주입되지 않은 상태에서 객체가 생성될 수 있기 때문에 취약할 수 있습니다. setter 주입은 필드 주입과 생성자 주입보다 유연하게 의존성을 주입할 수 있지만, 코드가 지저분해질 수 있습니다.

 

정리


1. 순환 참조를 방지

2. 코드가 깨끗하고 테스트하기 쉽다.

3. 불변성을 보장합니다.(final)

728x90
반응형

댓글