본문 바로가기

IT

스프링 의존 관계 주입(DI)

728x90

자동차의 바퀴를 교체하기 위해서 우리는 자동차 전체를 교체할 필요 없이 우리는 바퀴만 바꿔 갈아끼우면 된다. 

객체 지향 프로그래밍에 장점이 이것이라고 생각한다. 클래스의 변경이 필요하면 다른 클래스의 영향을 끼치지 않으면서 변경이 가능하도록 우리는 구현이 가능하다. 이러한 작업을 더 수월하게 진행할 수 있도록 도입된 기능이  DI(Dependency Injection)와 IoC(Inversion of Control) 이다. 

자바로 객체를 생성할 때 우리는 new 연산자를 이용하여 리모콘을 생성하여 사용하였다. 하지만 DI는 컨테이너가 new하지 않고 직접 인스턴스를 생성시켜주는 작업을 말한다. 코드에 직접적인 연관 관계가 발생하지 않아 느슨한 결합이 가능하다. 심지어 싱글톤으로 하나만 사용되기 때문에 무척 유용하다.

  • 클래스들 간 의존 관계를 최소화 할 수 있다.
  • 프로젝트 유지보수가 용이하다.
  • 기존에는 개발자가 직접 객체의 생성과 소멸을 제어했는데 DI로 인해 객체의 생성과 소멸 등 클래스간 의존관계를 스프링 컨테이너가 제어해준다.  

이처럼 그 의존 관계를 외부에서 결정하는 것을 DI(의존 관계 주입)라 한다. DI는 객체의 생성, 소멸, 의존 관계를 개발자가 직접 설정하는 것이 아니라  스프링 프레임워크가 제어한다. 기존에는 개발자가 직접 객체를 생성해줬던 반면에 스프링 프레임워크에서는 객체의 제어를 스프링이 직접 담당해주는 IoC(제어의 역전) 특징을 가진다.

 

IoC =>  Inversion of Control의 줄임말이며, 제어의 역전이라고 한다. 스프링 애플리케이션에서는 오브젝트(빈)의 생성과 의존 관계 설정, 사용, 제거 등의 작업을 애플리케이션 코드 대신 스프링 컨테이너가 담당한다.이를 스프링 컨테이너가 코드 대신 오브젝트에 대한 제어권을 갖고 있다고 해서 IoC라고 부른다. 따라서, 스프링 컨테이너를 IoC 컨테이너라고도 부른다.

IoC 컨테이너란? => 스프링에서는 IoC를 담당하는 컨테이너를 빈 팩토리, DI 컨테이너, 애플리케이션 컨텍스트라고 부른다. 오브젝트의 생성과 오브젝트 사이의 런타임 관계를 설정하는 DI 관점으로 보면, 컨테이너를 빈 팩토리 또는 DI 컨테이너라고 부른다. 그러나 스프링 컨테이너는 단순한 DI 작업보다 더 많은 일을 하는데, DI를 위한 빈 팩토리에 여러 가지 기능을 추가한 것을 애플리케이션 컨텍스트라고 한다. 정리하자면, 애플리케이션 컨텍스트는 그 자체로 IoC와 DI 그 이상의 기능을 가졌다고 보면 된다.

의존 관계 주입은 필드, 생성자, setter 세가지 방법으로 주입할 수 있다.

필드 주입

@Service
public class BurgerService {

    @Autowired
    private BurgerRecipe burgerRecipe;
}

장점 => 사용하기 편리하다.

단점 => 단일 책임 원칙 위반 가능성이 커진다. 하나의 클래스가 많은 책임을 갖게 될 가능성이 높다

        => 의존 관계를 파악하기 힘들다

        => DI 컨테이너와 결합도가 커지고 순환 참조 가능성이 커진다.

 

setter 주입

@Service
public class BurgerService {

    private BurgerRecipe burgerRecipe;

        @Autowired
    public void setBurgerRecipe(BurgerRecipe burgerRecipe) {
        this.burgerRecipe = burgerRecipe;
    }
}

 

장점 => 선택적인 의존성을 사용할 수 있다.

단점 => 선택적인 의존성을 사용할 수 있다는 것은 BurgerService에 모든 구현체를 주입하지 않아도 burgerRecipe 객체를 생성할 수 있고, 객체의 메소드를 호출할 수 있다. 즉, 주입받지 않은 구현체를 사용하는 메소드에서 NPE가 발생한다.

 

생성자 주입

@Service
public class BurgerService {

    private BurgerRecipe burgerRecipe;

        @Autowired
    public BurgerRecipe(BurgerRecipe burgerRecipe) {
        this.burgerRecipe = burgerRecipe;
    }
}

생성자에 @Autowired 어노테이션을 붙여 의존성을 주입받을 수 있으며, 가장 권장되는 주입 방식이다.

장점 => 의존 관계를 모두 주입 해야만 객체 생성이 가능하므로 NPE를 방지할 수 있다.

        => 불변성을 보장할 수 있다.

        => 순환 참조를 컴파일 단계에서 찾아낼 수 있다.

 단점 => 의존성을 주입하기 번거롭고, 생성자 인자가 많아지면 부담이 된다.

'IT' 카테고리의 다른 글

Spring MVC 구조  (0) 2022.08.22
트리거 (TRIGGER)  (0) 2022.08.10
스프링 어노테이션 정리  (1) 2022.08.09
Spring Security  (0) 2022.08.09
인터페이스와 추상클래스  (0) 2022.08.09