본문 바로가기
springboot

[springboot] DI(Dependency injection)

by 개발LOG 2025. 1. 12.
반응형

DI(Dependency injection)클래스가 자신이 필요한 의존 객체(즉, 다른 클래스의 인스턴스)를 스스로 생성하지 않고 외부에서 제공받는 방식입니다. 즉, 의존성(다른 객체)을 주입해줌으로써 객체 간의 결합도를 낮추고, 객체의 생성과 관리의 책임을 외부에 위임합니다.

1. 스프링 부트에서 DI 설정 기본 구조

스프링 부트에서 DI를 사용하는 과정은 크게 두 가지 주요 단계로 나눌 수 있습니다:

  1. 컴포넌트 스캔: @Component 및 그 하위 어노테이션(@Service, @Repository, @Controller 등)을 사용하여 객체를 스프링 컨테이너에 등록.
  2. 자동 의존성 주입: @Autowired를 사용하여 의존성 객체를 주입받기.

스프링 부트는 기본적으로 어노테이션 기반의 설정을 사용하며, 자동 컴포넌트 스캔이 활성화되어 있기 때문에, 특별한 설정 없이도 빈 등록 및 의존성 주입이 가능합니다.

 

2. 의존성 주입(DI) 두 가지 방법

(1) 생성자 주입 (Constructor Injection)

생성자 주입은 의존하는 객체가 생성자 매개변수로 전달되는 방식입니다. 이는 불변 객체를 보장하고, 의존성이 없으면 객체를 생성할 수 없기 때문에 컴파일 타임에 의존성을 강제로 확인할 수 있습니다.

@Component
public class MyService {
    private final MyRepository myRepository;

    // 생성자 주입
    @Autowired
    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void performService() {
        myRepository.doSomething();
    }
}

@Component
public class MyRepository {
    public void doSomething() {
        System.out.println("Doing something!");
    }
}
  • @Autowired: 생성자에 @Autowired 애너테이션을 붙여 스프링이 자동으로 의존성 객체를 주입하도록 합니다. 생성자가 하나일 경우 @Autowired는 생략할 수 있습니다.

(2) 세터 주입 (Setter Injection)

세터 주입은 객체의 세터 메서드를 통해 의존성을 주입하는 방식입니다. 이 방식은 객체의 상태를 수정할 수 있는 유연성을 제공하지만, 객체가 생성된 후 의존성을 주입할 수 있기 때문에 불변성을 보장할 수 없습니다.

@Component
public class MyService {
    private MyRepository myRepository;

    // 세터 주입
    @Autowired
    public void setMyRepository(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void performService() {
        myRepository.doSomething();
    }
}

 

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

생성자 주입을 사용하는 것이 불변성을 보장하고 테스트 용이성을 높이기 때문에 가장 권장됩니다.

 

4. Lombok에서 제공하는 생성자 관련 어노테이션

@AllArgsConstructor , @RequiredArgsConstructor 차이

 

(1)  @AllArgsConstructor

@AllArgsConstructor는 클래스에 정의된 모든 필드를 매개변수로 갖는 생성자를 자동으로 생성하는 Lombok 어노테이션입니다. 즉, 모든 필드를 주입할 수 있는 생성자를 만듭니다.

  • 모든 필드가 주입 가능한 생성자가 만들어집니다.
  • **final**이 붙은 필드도 포함되며, 필드의 타입에 관계없이 모든 필드를 생성자 매개변수로 사용합니다.
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class MyService {
    private final MyRepository myRepository;
    private MyOtherRepository myOtherRepository;

    public void performService() {
        myRepository.doSomething();
        myOtherRepository.doSomethingElse();
    }
}

final이 붙던 안붙던 상관 없음.  @AllArgsConstructor는 모든 필드 생성자 주입

myRepository와 myOtherRepository 생성자 주입 됨

 

(2) @RequiredArgsConstructor

@RequiredArgsConstructor는 final 필드@NonNull 어노테이션이 붙은 필드에 대해서만 생성자를 자동으로 생성하는 Lombok 어노테이션입니다.

  • final 필드 또는 **@NonNull**이 붙은 필드들만 생성자 매개변수로 포함됩니다.
  • 즉, 주입이 필요한 필드들만 생성자의 매개변수로 포함되며, final 필드가 아닌 @NonNull 필드는 NULL이 아니어야 한다는 제약을 추가할 때 사용됩니다.
import lombok.RequiredArgsConstructor;
import lombok.NonNull;

@RequiredArgsConstructor
public class MyService {
    private final MyRepository myRepository;  // final 필드
    private @NonNull MyOtherRepository myOtherRepository;  // @NonNull 필드
    private SubRepository subRepository;

    public void performService() {
        myRepository.doSomething();
    }
}

myRepository와 myOtherRepository 만 생성자 주입되고, subRepository는 생성자에 포함되지 않으며 주입도 안됨.

 

차이점 정리

특징   @AllArgsConstructor @RequiredArgsConstructor
생성자에 포함되는 필드   클래스의 모든 필드 (단, final 필드는 반드시 주입) final 필드와 **@NonNull**이 붙은 필드들만 포함
필드 제약   필드가 final인지 여부와 관계없이 모든 필드를 생성자에 포함 final이거나 @NonNull 어노테이션이 붙은 필드만 포함
사용 예   모든 필드를 매개변수로 사용하는 생성자를 생성 주입이 필요한 필드만 매개변수로 사용하는 생성자를 생성

결론

  • @AllArgsConstructor는 모든 필드를 매개변수로 갖는 생성자를 생성하며, 주로 모든 필드를 주입해야 할 때 사용됩니다.
  • @RequiredArgsConstructor는 final 필드 또는 **@NonNull**이 붙은 필드에 대해서만 생성자를 생성하며, 주로 주입이 반드시 필요한 필드만 주입하고 싶을 때 사용됩니다.
반응형