본문 바로가기

OOP

DI 방법과 장단점

반응형

DI 방법

의존성 주입 방법에는 다양한 방법이 존재한다.

  • 필드 주입
  • 수정자(setter) 주입
  • 생성자 주입

각 방법의 장단점과, 생성자 주입을 사용해야하는 이유를 알아보자.

 

필드 주입

필드에 @Autowired 어노테이션만 붙여주면 자동으로 의존성 주입이 된다.
@Controller
public class Controller{
  @Autowired 
  private Service service;
}

 

코드가 간결한 것이 장점이지만, 반대로 그렇기 때문에 의존관계를 파악하기 힘들다.

또한 외부에서 접근이 불가하며, 필드가 final 변수일 경우 @Autowired 어노테이션을 쓸 수 없다.

 

수정자(setter) 주입

Setter 메소드에 @Autowired 어노테이션을 붙이는 방법이다.
@Controller 
public class Controller{
   private Service service;

   @Autowired 
   public setService(Service service){
     this.service = service; 
   }
}

 

setter 메서드는 public 이기 때문에, 객체 변경이 어디서든 가능해진다는 단점이 있다.

 

필드 주입수정자 주입은 의존성이 있는 객체가 생성되지 않아도
이를 포함하고 있는 객체가 생성 가능(컴파일 시 오류 미발생)하여 런타임 시에 오류가 발생할 수 있다.
또한 의존성 주입 없이 사용 시 객체를 사용하는 부분에서 NullPointerException 발생 가능성이 존재한다.
또한 선언과 함께 초기화되어야 하는 final을 사용할 수 없다.

 

생성자 주입

생성자에 @Autowired 애노테이션을 붙여 의존성을 주입받는 방법이다.
Spring 4.3 부터 클래스의 생성자가 하나이고, 그 생성자로 주입받을 객체가 Bean으로 등록되어 있다면 @Autowired를 생략할 수 있다.
Spring 프레임워크에서 권장하는 방법이다.
@Controller 
public class Controller{
   private Service service;

   @Autowired 
   public Controller(Service service){
     this.service = service; 
   }
}

 

그렇다면 Spring 프레임워크에서 생성자 주입 방식을 권장하는 이유는 무엇일까?

 

NPE 방지 및 컴파일 시 오류 감지

생성자에서 의존관계 주입이 일어나기 때문에, 객체가 생성 될 때 의존 객체의 null 여부를 검사하므로 컴파일 시에 오류를 감지 할 수 있다

또한 null을 주입하지 않는 한 NullPointerException은 발생하지 않는다.

 

final 키워드 사용 가능

final 변수는 생성자에서 초기화가 가능하기 때문이다.

 

순환 참조 방지 (in Spring)

예를 들어, 닭 객체와 달걀 객체의 순환 참조를 필드 주입 방식으로 구현해보자.

@Component
public class Chicken {
    @Autowired
    Egg egg;

    public void layEgg(){
        egg.becomeChicken();
    }
}

닭은 달걀을 낳고, 달걀은 닭이 된다.

 

@Component
public class Egg {
    @Autowired
    Chicken chicken;

    public void becomeChicken() {
        chicken.layEgg();
    }
}

달걀은 닭이 되고, 닭은 달걀을 낳는다.

 

위와 같이 서로가 서로의 객체를 참조하며 실행되는 메서드가 수행되면, 무한루프 상태가 되어 StackOverflow 에러가 발생하게 된다.

이 문제가 필드/수정자 주입에서는 런타임 시 발견되지만, 생성자 주입 시에는 컴파일 시 발견 가능하다.

 

이는 객체의 생성 시점인 애플리케이션 구동 시점에 에러가 발생하기 때문이다.

(Spring Bean 등록 시 객체를 생성하는 과정에서 순환참조 발생)

new Chicken(new Egg(new Chicken(new Egg()...)))

 

 

reference

- https://mangkyu.tistory.com/125

- https://velog.io/@walker/Spring-%EC%99%9C-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%A3%BC%EC%9E%85%EC%9D%B4-%EA%B6%8C%EC%9E%A5%EB%90%98%EB%A9%B0-%EC%88%9C%ED%99%98%EC%B0%B8%EC%A1%B0%EB%9E%80-%EB%AD%98%EA%B9%8C

반응형

'OOP' 카테고리의 다른 글

IoC와 DI  (0) 2023.03.27
OOP 란?  (0) 2021.08.31