[Spring] DI(Dependency Injection) 의존성 주입

지니·2025년 4월 16일

Spring

목록 보기
5/13
post-thumbnail

1. Dependency Injection 개요


1-1. 의존성이란? 지금까지 우리는?

class A{
	B b = new B();
}

class B{
	public B(){}
}

🤔 위의 코드를 한 번 보자.

현재 A라는 클래스 안에서 B라는 객체를 사용하고 있다. 그리고 사용하기 위해 new라는 키워드를 통해 객체를 직접 생성해서 사용하고 있다. 이런 경우 A라는 클래스가 B에 의존하고 있는 것이다. 이 경우에 B의 다른 구현체로 바꾸고 싶다면 A 코드를 직접 수정해야 한다.
현재 A가 B에 너무 강하게 의존하고 있기 때문에 유지보수성, 확장, 테스트의 어려움이라는 문제가 발생한다. 이 문제의 해답이 DI이다.

1-2. Dependency Injection란?

Dependency Injection(의존성 주입)객체 간의 의존 관계IoC Container가 빈의 설정 정보를 바탕으로 자동적으로 연결해주는 것을 의미한다.

1-1에서 작성한 코드에 의존성 주입을 한다면⁉️

@Component
class A {
    private final B b;

    @Autowired  // 의존성 주입 by.생성자
    public A(B b) {
        this.b = b;
    }
}

@Component
class B {
    public B() {}
}

2. 의존성을 주입하는 방식


의존성을 주입하는 방식을 예제로 볼 것인데, 의존성을 주입하는 과정 그 자체에 대해서만 보여줄 것이다. 그래서 주입 방식을 보기 전에 주입되는 객체가와 사용되는 부분에 관해 먼저 짚고 넘어갈 것이다.

  • BookDAO : 인터페이스
  • BookDAOImpl : BookDAO를 구현하고 있는 클래스로 @Repository 어노테이션을 통해 bean으로 등록되어 있다.
  • BookDTO : 도서 정보가 있는 DTO

2-1. 생성자 주입

@Service
public class BookService {

    private BookDAO bookDAO;

    public BookService(){}

    @Autowired
    public BookService(BookDAO bookDAO) {
        this.bookDAO = bookDAO;
    }
}

✅ Spring 4.3 버전 이후부터는 생성자가 1개 뿐이라면 어노테이션을 생략해도 자동으로 생성자 주입이 동작한다.

2-2. Setter 주입

@Service
public class BookService {

    private BookDAO bookDAO;

    @Autowired(required = false)
    public void setBookDAO(BookDAO bookDAO){
        this.bookDAO = bookDAO;
    }
}
  • 의존성 주입이 옵션으로 수행될 수 있도록 처리할 때 유용하게 사용된다.
  • 여기에서 required 속성을 false로 설정하면 의존 대상의 bean이 존재하지 않는 경우에 의존성을 형성하지 않는다.

2-3. Field 주입

@Service
public class BookService {

    @Autowired
    private BookDAO bookDAO;

2-4. 생성자 주입을 사용하자⭐

우리는 의존성을 주입하는 3가지 방법을 배웠다. 그런데 Spring에서는 이 3가지 방법 중에서 "생성자 주입"을 권장한다.

Spring : “We recommend constructor injection for mandatory dependencies and setter injection for optional dependencies.”

✅ Why : 왜 생성자 주입이 권장될까❓

  • 객체가 생성 될 때 모든 의존성이 주입 되기 때문에 의존성을 보장할 수 있다.

    • 필드, setter 주입은 의존성이 주입되지 않아도 객체 생성이 가능하다. 이 때, 메소드가 호출 되면 런타임 오류가 발생하게 된다.
    • 생성자 주입의 경우 의존성이 있는 객체가 생성되지 않으면 객체 생성이 불가능 하다. 결과적으로 어플리케이션을 실행 할 때 오류가 발생한다.
  • 객체의 불변성을 보장할 수 있다.

    • 필드에 final 키워드를 사용할 수 있다.
    • 객체의 생성 이후엔 의존성을 변경할 수 있기 때문에 안전성이 보장된다.
  • 해당 객체가 어떤 의존성을 가지고 있는지 명확하게 알 수 있기 때문에 코드 가독성이 좋다.

  • DI 컨테이너와 결합도가 낮기 때문에 테스트 하기 좋다. 테스트를 할 때 스프링 컨테이너 없이 테스트를 할 수 있다.

  • Lombok의 @RequiredArgsConstructor 어노테이션과 결합되어 유용하게 사용할 수 있다.

    • 이 어노테이션을 붙이면 모든 final 필드에 대한 생성자를 자동으로 만들어 준다.

0개의 댓글