@Autowired란?

HMS·2023년 12월 8일

의존성 주입(Dependency Injection)

의존성 주입(Dependency Injection, DI)은 객체들 간의 의존 관계를 외부에서 주입하는 프로그래밍 패턴이다. 이 패턴은 객체 내부에서 직접적으로 의존성을 생성하는 것이 아니라, 스프링 컨테이너에서 필요한 의존성을 제공함으로써 모듈 간의 결합도를 낮추고 유연성 및 재사용성을 높인다.

@Autowired

@Autowired는 스프링에서 의존성을 자동으로 주입할 때 사용하는 어노테이션이다. 스프링 컨테이너는 @Autowired가 붙은 필드, 생성자, 세터 메서드 등에 자동으로 관련 의존성(빈)을 주입한다.

필드 주입(Field Injection)

  • 방법: 클래스 내부의 필드에 @Autowired를 선언하여 의존성을 주입한다.
  • 장점: 코드가 간결하다.
    설정이 간단하고 추가적인 설정이 필요없다.
  • 단점: 의존성이 숨겨져 있어 테스트가 어렵고, 변경 불가능한 의존성을 만들 수 있다. 순환 참조의 위험이 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PostService {

// 필드에 @Autowired 직접 선언
    @Autowired
    private PostMapper postMapper;

}

수정자 주입(Setter Injection)

  • 방법: setter를 생성하고 메소드 위에 @Autowired를 선언하여 의존성을 주입한다.
    의존성이 선택적으로 필요한 경우 사용한다.
  • 장점: 생성자에 모든 의존성을 기술하면 과도하게 복잡해질 수 있는것을 선택적으로 나눠 주입할 수 있게 부담을 덜어준다.
    생성자 주입과 setter주입을 상황에 맞게 분배하여 사용할 수 있다.
  • 단점: 의존성 주입 대상 필드에 final 선언이 불가하다.

생성자 주입(Constructor Injection)

  • 방법: 클래스의 생성자에 @Autowired를 선언함으로써 의존성을 주입한다. 스프링 4.3 이후로는 생성자가 하나인 경우 @Autowired 생략 가능.
    또한 @RequiredArgsConstructor를 사용하므로 써 생성자를 자동생성 하여 주입할 수도 있다.
  • 장점: 불변성을 보장하고, 의존성이 명확하게 드러난다. 테스트가 용이하다.
  • 단점: 의존성이 많은 경우 생성자의 파라미터가 복잡해질 수 있다.
  • 생성자 주입이 권장되는 이유: 생성시점에 의존성이 완전히 주입되어야 하는 객체의 불변성을 보장하기 때문이다. 필드주입시에는 이러한 불변성을 보장하기 어렵다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PostService {

    private PostMapper postMapper;
    
    @Autowired
    puvlic PostService(PostMapper postMapper){
    this.postMapper = postMapper;
    }

}

@RequiredArgsConstructor

@RequiredArgsConstructor는 Lombok 라이브러리의 어노테이션으로, final이나 @NonNull 필드에 대한 생성자를 자동으로 생성한다. 이 어노테이션을 사용하면 필요한 의존성만을 포함하는 생성자를 자동으로 만들어주므로, 생성자 주입 방식에서 코드를 더욱 간결하게 만들 수 있다.

순환참조?

순환 참조란 두개 이상의 클래스가 서로 직접적이거나 간접적으로 참조하는 상황을 말한다.
의존성 주입을 하는 환경에서 문제가 될 수 있다.

public class ClassA {
    private ClassB classB;

    // ClassA의 생성자 또는 세터에서 ClassB의 인스턴스를 주입받음
    public ClassA(ClassB classB) {
        this.classB = classB;
    }
}

public class ClassB {
    private ClassA classA;

    // ClassB의 생성자 또는 세터에서 ClassA의 인스턴스를 주입받음
    public ClassB(ClassA classA) {
        this.classA = classA;
    }
}

ClassA는 ClassB의 인스턴스를 필요로 하며, ClassB 역시 ClassA의 인스턴스를 필요로 한다. 이러한 구조는 서로가 서로를 필요로 하는 순환 참조가 발생하게 된다.

순환 참조는 코드의 이해와 유지보수를 어렵게 만들 수 있다. 클래스간 의존성이 복잡해지고 코드를 추적하기 어려워 지기 때문이다.

profile
안녕하세요

0개의 댓글