IoC(Inversion of Control) · DI(Dependency Injection)
by 볼빵빵오춘기IoC(IoC, Inversion of Control)
일반적인 자바 개발의 경우 객체를 사용하기 위해 new 키워드를 사용하여 새로운 객체를 생성하여 사용한다.
즉, 사용하려는 객체를 선언하고 해당 객체의 의존성을 생성한 후 객체에 제공하는 기능을 사용한다.
객체를 생성하고 사용하는 일련의 작업을 개발자가 직접 제어하는 구조이다.
하지만 제어 역전(IoC;IoC, Inversion of Control)을 특징으로 하는 스프링은 기존 자바 개발 방식과 다르게 동작한다.
IoC를 적용한 환경에서는 사용할 객체를 직접 생성하지 않고 객체의 생명주기 관리를 외부에 위임한다.
여기서 '외부'는 스프링 컨테이너 또는 IoC 컨테이너를 의미한다.
객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 제어 역전이라고 부르며, 제어 역전을 통해 의존성 주입(DI;Dependency Injection), 관점 지향 프로그래밍(AOP;Aspect-Oriented Programming) 등이 가능하다.
스프링을 사용하면 객체의 제어권을 컨테이너로 넘기기 떄문에 개발자는 비즈니스 로직을 작성하는 데 더 집중할 수 있다.
의존성 주입(DI;Dependency Injection)
- 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식을 의미한다.
- @Autowired 어노테이션을 붙여줌으로서 의존성을 주입할 수 있다.
- 스프링 4.3 이후 버전은 생성자를 통해 의존성을 주입할 때 @Autowired를 생략가능하다.
- 스프링 공식 문서에서 권장하는 의존성 주입 방법은 생성자를 통해 의존성을 주입받는 방식이다.
다른 방식과는 다르게 생성자를 통해 의존성을 주입받는 방식은 레퍼런스 객체없이는 객체를 초기화 할 수 없게 설계할 수 있기 떄문이다.
의존성 주입 방법
- 생성자를 통한 의존성 주입
- 필드 객체 선언을 통한 의존성 주입
- setter 메서드를 통한 의존성 주입
// 생성자를 통한 의존성 주입
@RestController
public class DIController{
private final MyService myService;
@Autowired
public DiController(MyService myService){
this.myService = myService
}
}
// 필드 객체 선언을 통한 의존성 주입
@RestController
public class DIController{
@Autowired
private MyService myService;
}
// setter 메서드를 통한 의존성 주입
@RestController
public class DIController{
MyService myService;
@Autowired
public void setMyService(MyService myService){
this.myService = myService
}
}
객체 직접 생성 vs 외부에서 생성되어 주입(의존성 주입)
클래스 내에 객체를 직접 생성
class OwnerController {
private OwnerRepository repo = new OwnerRepository();
}
- 강한 결합
OwnerController는 특정 OwnerRepository 구현에 강하게 결합되어 있다.
만약 OwnerRepository의 구현을 바꾸거나 수정해야 한다면, OwnerController의 코드도 변경해야 한다. -
테스트 어려움
단위 테스트를 할 때, OwnerRepository 객체를 모의(Mock) 객체로 교체할 수 없다.
OwnerController의 테스트가 어려워진다. - 유연성 부족
다른 구현체를 사용할 수 있는 유연성이 떨어진다.
ex, 다른 데이터베이스나 저장소 전략을 사용하고 싶을 때 변경이 어렵다. - 객체의 생명주기가 종속적
OwnerRepository는 필요할 때마다 새로 생성된다.
또한 OwnerController 객체가 더 이상 사용되지 않고 가비지 컬렉션의 대상이 될 때, OwnerRepository 객체도 가비지 컬렉션 대상이 된다.
즉, OwnerRepository객체는 OwnerController 객체의 생명주기에 종속적이다.
의존성 주입
public class OwnerController {
private final OwnerRepository repo;
@Autowired
public OwnerController(OwnerRepository repo) {
this.repo = repo;
}
}
- 낮은 결합도
OwnerController는 OwnerRepository의 구체적인 구현체에 결합되지 않는다.
이를 통해 코드의 유연성과 재사용성을 높일 수 있다. - 테스트 용이성
단위 테스트 시, 쉽게 OwnerRepository를 모의 객체(Mock Object)로 대체할 수 있다.
이를 통해 독립적이고 더 효율적인 테스트가 가능하다.더보기Mock객체란 더미부푼을 만드는 것인데 Mock객체를 이용하게 되면 인스턴스를 만들어서 사용하게 되며 단위테스트할 때 대체하기 쉬운 이유는 외부에 띄어져 있는 IoC컨테이너에있는 객체를 주입받는 과정에서 Mock이라는 객체를 대체해서 넣어 줄 수 있기 때문이다.
코드의 의존성을 분리하지 않았다면 Mock객체로 대입할 수가 없다. - 유연성
같은 인터페이스를 구현한 다양한 객체들을 주입할 수 있다.
ex, 다른 종류의 OwnerRepository(예: JpaOwnerRepository나 MongoOwnerRepository)를 손쉽게 주입할 수 있다. - 애플리케이션 컨텍스트와 함께 생성, 종료 시까지 유지
OwnerRepository의 생명 주기는 IoC 컨테이너에 의해 관리된다.
OwnerRepository는 싱글톤 스코프로 설정되며, 애플리케이션 컨텍스트와 함께 생성되어 애플리케이션 종료 시까지 유지된다.
이것은 해당 객체가 애플리케이션의 여러 구성 요소들에 의해 재사용될 수 있음을 알 수 있다.
직접 생성 | 의존성 주입 | |
결합도 | 강한결합이다. | 낮은 결합이다. |
테스트 | 어렵다. | 용이하다. |
유연성 | 유연하지못하다. | 유연하다. |
생명주기 | 필요할 때 생성이 되며, 고수준 모듈이 가비지컬렉션이되면 저수준모듈도 같이 가비지컬렉션이 된다. |
애플리케이션 컨텍스트와 함께 생성되어, 애플리케이션 종료 시까지 유지된다. |
※ 싱글톤
디자인 패턴 중 하나로, 특정 클래스의 인스턴스가 오직 하나만 생성되도록 보장하고, 그 인스턴스에 접근할 수 있는 전역적인 방법을 제공하는 패턴이다. 이를 통해 시스템 전역에서 하나의 객체를 공유하여 사용하도록 한다.
정리하자면
- 의존성 역전 원칙(Dependency Inversion Principle, DIP)은 객체 지향 설계의 SOLID 원칙 중 하나로, 고수준 모듈(예: OwnerController)이 저수준 모듈(예: OwnerRepository)에 의존하지 않고, 추상화된 인터페이스에 의존하게 함으로써 모듈 간 결합도를 낮추는 것을 목표한다.
Spring에서는 이 원칙을 IoC 컨테이너를 통해 구현한다. IoC 컨테이너는 필요한 의존성을 생성하고, 관리하고, 주입한다.
⇒ 개발자가 객체 생성 및 라이프사이클 관리를 직접 하지 않아도 된다. - @Autowired를 사용하여 Spring이 Repository의 인스턴스를 자동으로 주입하게 된다.
⇒ Controller는 Repository의 구체적인 구현에 대해 알 필요가 없다. - 직접 생성은 강한 결합을 만들고, 테스트하기 어렵고, 유연성이 부족하다.
IoC와 의존성 주입을 사용하면 낮은 결합도, 높은 유연성, 더 쉬운 테스트가 가능하다. - Spring IoC 컨테이너는 객체를 생성하고, 관리하고, 주입하여 개발자가 직접 객체 관리를 하지 않아도 되도록 한다.
⇒ Spring과 같은 프레임워크에서는 의존성 주입과 제어의 역전을 사용하여 더 유연하고, 확장 가능하며, 유지 관리하기 쉬운 코드를 작성할 수 있게 한다.
'👩🏻💻 About 프로그래밍 > spring' 카테고리의 다른 글
AOP (0) | 2024.09.09 |
---|---|
Spring boot 게시판 목록 페이징(feat. JPA) (0) | 2024.08.14 |
Spring Data JPA Entity 연관관계 (0) | 2024.08.13 |
Spring boot 게시판 댓글 CRUD (0) | 2024.08.13 |
Spring boot 게시판 만들기(게시판 CRUD) (0) | 2024.08.13 |
블로그의 정보
Hello 춘기's world
볼빵빵오춘기