Spring에서의 IoC와 DI

이승주·2024년 3월 26일
0

제어의 역전  (Inversion Of Control, IoC)

프로그램의 흐름을 직접 제어하는 것이 아니라 외부에 제어권을 넘겨 관리하게 하는 것을 제어의 역전이라고한다.

상세히 말하면 객체의 생성과 관리를 외부에서 한다면 제어권을 넘기게 되어 제어의 역전이 발생한 것이다.


프레임워크와 라이브러리

프레임워크는 제어의 역전 개념이 적용된 대표적인 기술이다.
프레임워크와 라이브러리를 구분할 때 IOC 개념이 중요하다.

Library

개발자는 필요한 Library 들을 선택하고, 연결하고, 설정하는 모든걸 다 직접 해야함

세부적으로 보면 라이브러리를 통해 객체를 생성하고
메소드를 호출하는 것을 개발자가 직접하기에 제어권이
코드 자체(개발자)에게 있는 것이다.

Framework

개발자가 직접 구현한것 혹은 Library 들을 연결하고, 설정하는 것들을 제공함

개발자가 기능 구현에 필요한 특정 코드를 프레임워크에 작성하면
프레임워크가 알아서 객체를 생성하고 메소드를 호출해준다.
즉 제어권이 프레임워크에 있는 것이다.


Spring 프레임워크에서의 IoC

스프링에서는 사용할 객체를 직접 생성하지 않고 객체의 생성과 생명주기 관련해서는 Spring 컨테이너에 위임을 하여 제어권을 넘기게 된다. 이것이 Spring에서의 제어의 역전 IoC다.

IoC를 통해 ID(의존성 주입), 관점 지향 프로그래밍(AOP)등이 가능해지는 것이다. 이번 포스팅 글에서는 Spring에서의 DI를 집중적으로 다루어 보려고 한다.

빈 등록

빈 사용

  • @Autowired

의존성 주입(DI)

의존성 주입은 제어 역전의 방법 중 하나로, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식이다.

@Autowired

스프링 컨테이너에서 객체를 찾아 의존 객체 타입에 맞게 넣어준다.

의존관계 주입의 4가지 방법

  • 생성자 주입
  • 수정자 주입
  • 필드 주입
  • 일반 메서드 주입

생성자 주입

쉬운 이해를 위한 코드

@Component
public class OrderServiceImpl implements OrderService {
	 
	 private final MemberRepository memberRepository;
	 private final DiscountPolicy discountPolicy;
	 
 @Autowired
 public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicydiscountPolicy) {
		 this.memberRepository = memberRepository;
		 this.discountPolicy = discountPolicy;
 }
}
  • 이름 그대로 생성자를 통해서 의존 관계를 주입 받는 방법
  • Final 적용 가능하여 생성자 호출시점에 의존 객체가 딱 1번만 주입되는 것이 보장된다. 의존 객체를 변경하지 않을 경우에 사용함

실제 현업에서 사용하는 코드(@RequiredArgConstructor + private final)

@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
	 
	 private final MemberRepository memberRepository;
	 private final DiscountPolicy discountPolicy;
	 
	
	/*  
	  public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicydiscountPolicy) {
		 this.memberRepository = memberRepository;
		 this.discountPolicy = discountPolicy;
 }
	 */
	 
}
  • @RequiredArgsConstructor 기능을 사용하면 final이 붙은 필드를 모아서 생성자를 자동으로 만들어줌
  • 주석 처리된 생성자가 RequiredArgsConstructor로 인해 생성되었지만 안 보이는 것임

수정자 주입

@Component
public class OrderServiceImpl implements OrderService {
 
	 private MemberRepository memberRepository;
	 private DiscountPolicy discountPolicy;
 
	 @Autowired
	 public void setMemberRepository(MemberRepository memberRepository) {
			 this.memberRepository = memberRepository;}
	 
	 @Autowired
	 public void setDiscountPolicy(DiscountPolicy discountPolicy) {
			 this.discountPolicy = discountPolicy;}
}
  • setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법
  • 선택, 변경 가능성이 있는 의존관계에 사용

필드 주입

@Component
public class OrderServiceImpl implements OrderService {
	 
	 @Autowired
	 private MemberRepository memberRepository;
	 
	 @Autowired
	 private DiscountPolicy discountPolicy;
}
  • 이름 그대로 필드에 바로 주입하는 방법
  • 코드가 간결해서 많은 개발자들을 유혹하지만 외부에서 변경이 불가능해서 테스트 하기 힘들다는 치명적인 단점이 있음

Test 코드를 짤 때 순수 자바로 단위 Test Code를 만든다고 한다.
스프링을 띄우고 하나 하나 테스트를 돌리면 굉장히 시간이 오래 걸리기 때문이다.


일반 메서드 주입

@Component
public class OrderServiceImpl implements OrderService {
	 
	 private MemberRepository memberRepository;
	 private DiscountPolicy discountPolicy;

@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
		 this.memberRepository = memberRepository;
		 this.discountPolicy = discountPolicy;
 }
}
  • 일반 메서드를 통해서 주입 받는 방법
  • 한번에 여러 필드를 주입 받을 수 있다.
  • 생성자 주입과 다를게 많이 없어서 많이 사용하지 않는다고 한다.

결론

항상 생성자 주입을 선택하고 그리고 가끔 의존 객체를 변경할 상황이 생긴다면 수정자 주입을 선택하면 된다.
일반 메서드 주입, 필드 주입은 사용하지 않는게 좋다.


참고자료

  • Arron(ASAC_04)- Spring Boot 의 등장 및 특장점, 기본 Annotations
  • 김영한- 스프링 기본편(DI편)
  • 장정우- 스프링 부트 핵심가이드(P2~P11)
  • bitkunst- DI, IOC...
profile
반복되는 실수를 기록을 통해 줄여가보자!

0개의 댓글

관련 채용 정보