[Spring Framework] 생성자 주입을 사용해야하는 이유

🔍 의존성 주입(DI)

의존성 주입(Dependency Injection)은 객체 간의 의존 관계를 외부(IoC Container)로부터 주입받아 동적으로 의존관계를 성립시키는 방법이다. 스프링에서는 세 가지 주입 방법을 제공하지만, 그 중에서도 생성자 주입 방식을 권장한다.

의존성 주입 방법:

  1. 생성자 주입 (권장)
  2. Setter 주입
  3. 필드 주입

@Autowired 어노테이션

@Autowired 어노테이션은 스프링 컨테이너(IoC Container)에 등록된 빈(Bean) 중 타입이 일치하는 객체를 자동으로 주입해주는 어노테이션이다.


🏗️ 생성자 주입

생성자 주입은 생성자를 통해 의존 관계를 주입하는 방법이다.

1
2
3
4
5
6
7
8
9
10
11
@Service
public class UserService {
    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public UserService(UserRepository userRepository, MemberService memberService) {
        this.userRepository = userRepository;
        this.memberService = memberService;
    }
}

생성자가 하나만 있을 경우, @Autowired를 생략할 수 있다:

1
2
3
4
5
6
7
8
9
10
@Service
public class UserService {
    private UserRepository userRepository;
    private MemberService memberService;

    public UserService(UserRepository userRepository, MemberService memberService) {
        this.userRepository = userRepository;
        this.memberService = memberService;
    }
}

🔧 Setter 주입

Setter 주입은 Setter 메서드를 통해 의존 관계를 주입하는 방법이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class UserService {
    private UserRepository userRepository;
    private MemberService memberService;

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

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}

🏷️ 필드 주입

필드 주입은 필드에 직접 의존 관계를 주입하는 방법이다.

1
2
3
4
5
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
}

하지만 이 방식은 권장되지 않는다.

  1. 순환 참조를 예방할 수 없다.
    • 순환 참조 발생 시 런타임 단계에서야 오류를 잡아낼 수 있다.
  2. final을 사용할 수 없어 불변성을 보장받지 못한다.
    • 객체의 불변성을 보장할 수 없어 런타임 중 객체가 변경될 가능성이 있다.
  3. 의존성을 숨긴다. (Dependency Hiding)
    • 필드 주입은 Reflection API를 사용해 의존성이 외부로 노출된다.
  4. 테스트가 어렵다.
    • 스프링 컨테이너 없이 순수한 자바 코드로 단위 테스트를 작성하기 어렵다.

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

  1. 📌 객체의 불변성 확보
    • 생성자 주입은 객체 생성 시 1회만 호출되어 불변성을 보장한다.
    • 변경 가능성이 없거나 반드시 객체 주입이 필요한 경우에 강제할 수 있다.
  2. 🧪 테스트 코드 작성의 용이성
    • 순수한 자바 코드로 단위 테스트를 작성할 수 있다.
    • 컴파일 시점에 객체를 주입받아 테스트 코드를 작성할 수 있다.
  3. 🔒 final 키워드 사용 및 Lombok과의 결합
    • 필드에 final 키워드를 사용할 수 있어 컴파일 시점에 누락된 의존성을 확인할 수 있다.
    • Lombok의 @RequiredArgsConstructor와 결합하여 코드를 간결하게 작성할 수 있다.
    1
    2
    3
    4
    5
    6
    
    @Service
    @RequiredArgsConstructor
    public class UserService {
        private final UserRepository userRepository;
        private final MemberService memberService;
    }
    
  4. 🌱 스프링에 비침투적인 코드 작성
    • @Autowired 같은 스프링 어노테이션을 사용하지 않아도 되어 프레임워크에 독립적인 코드를 작성할 수 있다.
  5. 🔄 순환 참조 에러 방지
    • 애플리케이션 구동 시점(객체의 생성 시점)에 순환 참조 에러를 예방할 수 있다.
    • 필드 주입은 애플리케이션이 구동된 후 호출 시점에 에러가 발생하지만, 생성자 주입은 시작 시점에 에러를 확인할 수 있다.

참고

Leave a comment