본문 바로가기
Spring

[Spring Boot] IoC(제어의 역전, Inversion of Control) / DI(의존성 주입, Dependency Injection)

by 도전하는 린치핀 2024. 7. 28.

1. IoC(Inversion of Control)란

  • IoC는 Inversion of Control의 약자로 말 그대로 제어의 역전이라 한다.
  • 제어의 역전은 메서드나 객체의 호출 작업을 개발자가 아닌 프레임워크에게 제어권을 넘기는 행위다.
  • 스프링에서의 IoC는 Controller, Service와 같은 객체들의 동작을 개발자가 직접 구현하지만 해당 객체들의 호출 시점을 개발자가 제어하지 않는다.
  • 스프링 프레임워크가 요구하는 방식으로 메서드나 객체를 구현하면 해당 메서드와 객체의 생성, 호출, 소멸은 프레임워크가 알아서 해주는 것을 의미한다.
  • 이전까지는 개발자가 객체의 생성을 관리하며 제어했지만, 스프링을 사용하게 되면 스프링 컨테이너에게 제어권을 넘겨 스프링 컨테이너가 흐름을 제어하게 된다.

2. IoC의 장점

  • 객체간의 낮은 결합도 유지
  • 유연한 코드 작성
  • 가독성 증가
  • 코드 중복 방지
  • 유지 보수 용이

즉, IoC를 통해 객체를 클래스 내부에서 직접 생성하여 사용하지 않고 미리 생성해놓은 객체를 주입받아 사용하면 된다.

그렇다면 객체를 주입 받는다는 것은 무엇일까?

3. DI(Dependency Injection)란?

  • DI란 의존성 주입이라는 의미로, 객체를 직접 생성하는 것이 아닌 외부(IoC컨테이너, DI 컨테이너, 스프링 프레임워크)에서 주입시켜주는 방식
  • 의존성이랑 의존 대상 B라는 객체가 변하면 B 객체를 사용하는 A 객체에 영향이 생겨 B 객체의 변화가 A 객체에도 영향을 끼친다는 말이다.

4. DI의 장점

  • 의존관계 설정이 되지 않으면 컨파일 타임에 알 수 있다.
  • 의존성 주입이 필요한 필드를 final 키워드로 선언 가능하다
  • 스프링에서 순환 참조 감지 기능을 제공하며 순환 참조 시 에러를 보여준다.
  • 테스트 코드 작성이 용이하다.

5. 의존성 주입 방법

생성자 주입 ( Constructor Injection )

생성자 주입이란 생성자를 통해 의존관계를 주입하는 방법으로 생성자를 호출 시에 딱 한 번만 호출되는 것을 보장한다.
스프링 4.3 버전 이후라면 @Autowired를 생략해도 주입이 되며, 주입받는 필드에 final 키워드를 사용함으로써 주입돼야 하는 것을 보장한다.
아래는 예시 코드이다. 

@Controller
public class TestController {
	private final TestService testService;
    
    public TestController(TestService testService){
    	this.testService = testService;
    }
}

 

 

수정자 주입 ( Setter Injection)

수정자 주입이란 영어 그대로 setter를 사용하여 의존관계를 주입하는 방법이다. 수정 가능성이 존재하는 의존관계일 때 사용하며 자바 빈 프로퍼티 규약의 setter메서드 방식을 사용한다.
수정자 주입의 경우 final 키워드 선언이 불가능하며, setter 메서드에 @Autowired를 붙여 사용한다.

@Controller
public class TestController {
	private TestService testService;
    
    @Autowired
    public void setTestService(TestService testService){
    	this.testService = testService;
    }
}

 

필드 주입 ( Field Injection )

필드 주입이란 필드에 직접 의존관계를 주입하는 방법이다.
이는 코드가 짧아지는 장점이 있지만 외부에서 변경이 불가능하고 테스트 코드를 작성하기 힘들다는 단점이 존재한다.
또한 final 키워드 선언이 불가능해지고 의존관계를 파악하기 힘들어진다. 

 

@Controller
public class TestController {
	@Autowired
	private TestService testService;
}