Spring DI에 대하여

신준호·2023년 12월 31일
0
post-thumbnail

DI(Dependency Injection)이란

📢 DI란 의존 관계 주입 혹은 의존성 주입이라 불리고, Spring은 3가지 핵심 프로그래밍 모델(AOP, DI, IOC)을 지원하는데 그 중 하나가 바로 DI입니다. Spring은 객체의 의존 관계를 의존 관계 주입을 통해 관리를 합니다. DI는 외부에서 객체 간의 관계를 결정해 주는데 즉, 객체를 직접 생성하는 것이 아니라 외부에서 생성 후 주입시켜 주는 방식입니다.

Spring에서의 DI 방법 3가지

Spring에서 DI 방법에는 총 3가지 있습니다.

생성자 주입(Constructor Injection)

  • Spring 공식 문서에서도 생성자 주입을 권장할 만큼 현재 가장 권장되는 의존 관계 주입 방식입니다.
    • Spring 4.3부터는 @Autowired가 생략 가능해서 최근에는 생성자를 딱 1개 두고, @Autowired를 생략하는 방법을 주로 사용합니다.
    • Lombok 라이브러리의 @RequiredArgsConstructor를 함께 사용하면 생성자를 생략 가능해서 코드가 깔끔해지는 장점이 있습니다.
  • 오직 생성자 주입만이 final 키워드를 사용할 수 있고, 생성자를 통해 주입되는 방식입니다.
  • 생성자에서 의존관계 주입이 일어나기 때문에 객체가 생성 될 때 객체의 null 여부를 검사하므로 컴파일시에 오류를 발생시켜 런타임시에 오류가 발생하는 것을 방지해준다.
  • final 키워드를 사용해서 값이 한번 할당되면 변경할 수 없기에 객체의 불변성이 보장됩니다.
  • 초기에 할당되기에 NPE(Null Pointer Exception)이 절대 발생하지 않습니다.
  • @Autowired 사용
    public class Injection {
    
        private InjectionService injectionService;
        
        // 생성자 DI
        // @Autowired -> Spring4.3부터는 @Autowired 생략 가능
        public Injection(InjectionService injectionService) {
        	this.injectionService = injectionService;
        }
    }
    위에서는 생성자에 @Autowired 어노테이션을 사용했지만 Spring 4.3부터는 @Autowired를 생략 가능합니다. 생성자 주입이 가장 좋은 방법이지만, 매번 생성자를 만들어야 하고 코드가 길어질 수 있습니다.
  • @RequiredArgsConstructor 사용
    **@RequiredArgsConstructor
    public class Injection {
    
        private final InjectionService injectionService;
        
    }**
    @RequiredArgsConstructor은 ****룸북(Lombok)의 어노테이션 중 하나입니다. 해당 어노테이션은 final 키워드가 붙은 주입에만 생성자를 만들어기 떄문에 final 키워들르 사용하지 않으면 @AllArgsConstructor 어노테이션을 사용하면 됩니다.

필드 주입(Field Injection)

  • Bean으로 등록된 객체를 사용하고자 하는 클래스에 Filed로 선언한 뒤 @Autowired를 붙어주면 자동으로 의존 관계가 주입됩니다.(어찌 보면 가장 간단한 방법)
  • 참조 관계를 눈으로 확인하기 어렵고, 순환 참조를 막을 수 없습니다.
    • 예를 들어 A가 B를 가지고 있고, B가 A를 가지고 있어(순환 참조)실행 전까지 error를 잡을 수 없습니다.
  • 생성자 주입을 뺀 나머지(필드 주입, Setter 주입)은 모두 생성자 이후에 호출되므로, 필드에 final 키워드를 사용할 수 없습니다.
  • @Autowired 사용
    public class Injection {
    	@Autowired
        private InjectionService injectionService;
    }
    • 필드 주입의 장점
      • 위 코드처럼 코드가 간결해집니다
    • 필드 주입의 단점
      • Solid 원칙 중에 단일 책임 원칙(SRP)를 위반합니다.
      • Unit Test가 어렵습니다
      • final 키워드를 사용할 수 없어 객체가 변할 수 있습니다.

Setter 주입(Field Injection)

  • @Autowired 어노테이션을 사용하여 Setter 메소드를 통해 주입하는 방법
  • NPE(Null Pointer Exception)이 발생할 수 있다
  • 필드 주입처럼 생성자 이후에 호출되므로, 필드에 final 키워드를 사용할 수 없습니다.
  • @Autowired 사용
    **public class Injection {
    	
        private InjectionService injectionService;
        
        @Autowired
        public void setInjectionService( InjectionService injectionService) {
        	this.injectionService = injectionService;
        }
    }**

결론

생성자 주입을 써라

과거 Spring 3.X 버전까지는 권장하는 DI 방식이 Setter 주입,혹은 필드 주입을 사용했습니다. 하지만 Spring 4.3부터는 생성자 주입 방식을 사용하는 것이 좋습니다. 가끔 옵션이 필요한 경우 Setter 주입을 사용하고, 절대 필드 주입을 사용하지 않는 것이 좋습니다.

면접 예상 질문

DI란 무엇입니까?

✨ Spring은 객체의 의존 관계를 의존 관계 주입을 통해 관리를 합니다. DI는의존성 주입으로서 외부에서 객체 간의 관계를 결정해 주는데 즉, 객체를 직접 생성하는 것이 아니라 외부에서 생성 후 주입시켜 주는 방식입니다.

생성자 주입을 사용해야 하는 이유는 무엇입니까?

✨ 첫 번째는 생성자 주입을 사용하면 객체를 생성할 때 딱 1번만 호출되기 깨문에 객체의 불변성을 확보할 수 있습니다. 두 번째는 NPE(Null Pointer Exception)이 발생하지 않기 때문에 테스트 코드의 작성에 용이합니다. 세 번째는 생성자 주입을 사용하면 필드 객체에 final 키워드를 사용할 수 있으며, 컴파일 시점에 누락된 의존성을 확인할 수 있습니다. 또한 final 키워드를 붙이면 Lombok과 결합되어 코드를 간결하게 작성할 수도 있습니다.(ex @RequiredArgsConstructor) 마지막으로 생성 주입 방식은 순환참조도 컴파일시에 미리 파악 할 수 있습니다.

profile
개발 공부 일지

0개의 댓글