스프링 프레임워크의 핵심 3대 요소 중 IoC(제어의 역전) 용어를 정리하며 이해해보자.
스프링 핵심 3대 요소
1. IoC(Inversion of Control) - 제어의 역전
2. AOP(Aspect Oriented Programming) - 관점 지향 프로그래밍
3. PSA(Portable Service Abstraction) - 서비스 추상화
🔎 IoC (Inversion of Control)
스프링의 핵심 요소로 알려져 있어서, 스프링에서 처음 나온 개념인 것 같지만 아니다. (90년 중반, GoF의 디자인패턴에서도 이용어가 언급되었다고 한다.)
스프링에 국한되어 나온 개념이 아닌만큼, 디자인 패턴 중 하나인 템플릿 메서드 패턴에서도 IoC를 확인 할 수 있다.
※ IoC 이해에 집중하기위해 필요한 부분만 작성했기 때문에 템플릿 메서드 패턴의 내용은 추가로 정리하기로.
- 템플릿 메서드 패턴
아래 코드는 Pizza 주문을 처리하는 추상 클래스 (PizzaStore).
// 템플릿 메서드를 갖는 추상 클래스
abstract class PizzaStore {
// 주문하는 템플릿 메서드
// final 키워드로 자식 클래스에서 상위 템플릿을 오버라이딩해 마음대로 바꾸지 못하게 함
//제어권이 PizzaStore에 있다는 것을 알 수 있는 부분
public final void orderPizza() {
prepareDough();
addIngredients();
bake();
slice();
deliver();
}
// 추상 메서드 - 도우 준비
protected abstract void prepareDough();
// 추상 메서드 - 재료 추가
protected abstract void addIngredients();
// 기본 구현이 있는 메서드 - 굽기
protected void bake() {
System.out.println("Baking the pizza");
}
// 기본 구현이 있는 메서드 - 자르기
protected void slice() {
System.out.println("Slicing the pizza");
}
// 기본 구현이 있는 메서드 - 배달
protected void deliver() {
System.out.println("Delivering the pizza");
}
}
다음은 PizzaStore를 상속받아 구체적으로 구현한 클래스 (PepperoniPizzaStore).
// PizzaStore를 상속받는 구체적인 클래스
class PepperoniPizzaStore extends PizzaStore {
@Override
protected void prepareDough() {
System.out.println("Preparing Pepperoni pizza dough");
}
@Override
protected void addIngredients() {
System.out.println("Adding Pepperoni pizza ingredients");
}
// bake, slice, deliver는 기본 구현 사용
}
실행
public class PizzaOrderExample {
public static void main(String[] args) {
PizzaStore PepperoniPizzaStore = new PepperoniPizzaStore();
PepperoniPizzaStore.orderPizza();
}
}
하위 클래스인 PepperoniPizzaStore 에서 구현하는 코드는 상위 클래스가 어떻게 되는지 알 수 없다. 구체적으로 구현해야 하는 부분만 구현했을 뿐이고, 구현한 코드가 언제 어떤식으로 사용될 지는 상위 클래스(PizzaStore)에서 결정한다.
프레임워크에서 많은 부분에 이 패턴이 적용되어 있다고 한다.
이처럼 흐름의 제어가 제3자에게 위임되는 것을 IoC(제어의 역전) 라고 하며, '제3자'를 스프링에서는 "스프링 컨테이너" 라고 한다.
🔎 DI (Dependency Injection)
의존관계 주입. 용어의 뜻을 먼저 알아보자.
- 의존관계 (의존성)
파라미터나 지역변수 등으로 다른 객체를 참조하는 것을 의미.
보통 한 객체가 다른 객체를 사용할 때 의존성이 있다고 표현한다. 객체 지향 프로그래밍에서는 클래스나 모듈 간에 서로 협력하고 상 호 작용할 때 의존성이 발생한다.
예시) Cafe객체가 Americano 객체에 의존성이 있다. (Cafe가 Americano를 의존한다.)
public class Cafe {
private Americano americano;
}
- 주입
'약물을 넣다(주입)하다' , '냉각수를 주입하다' 와 같이 외부에서 어떤 것을 제공하는 형태를 말하는 것을 알 수 있다.
- 의존관계(의존성) + 주입
위 설명을 간단히 합하면 '의존성을 외부로부터 제공받는다.' 혹은 '의존관계를 외부에서 결정해준다.' 라고 해석 할 수 있다.
* 의존성은 다른 객체를 참조함으로 생기기 때문에 결국 의존성 주입은 다른 객체를 참조하기 위한 객체의 주소(레퍼런스)를 외부로부터 전달받는 것을 의미.
public class A {
//코드에서 객체를 생성하지 않고, 제3자(스프링 컨테이너)에게 B를 주입받는다.
@Autowired
private B b;
}
@Autowired 어노테이션은 객체를 주입받기 위해 스프링에서 사용하는 키워드 정도 라고 알고 넘어가자.
DI 용어의 이해를 돕기 위해 아래 토비의 스프링 도서에서 서술한 내용도 읽어보자.
"스프링이 여타 프레임워크와 차별화돼서 제공해주는 기능은 의존관계 주입이라는 새로운 용어를 사용할 때 분명하게 드러난다.
생략…
DI는 오브젝트 레퍼런스를 외부로부터 제공(주입)받고 이를 통해 여타 오브젝트와 다이내믹하게 의존관계가 만들어지는 것이 핵심"
추가로 DI라는 용어는 마틴파울러와 주변사람들이 모여 IoC에 범용적인 의미를 객체 주입이라는 의미를 명확히 하기 위해 만들어졌다고 한다. [마틴파울러 글 원문]
용어정리를 했으니 [다음 포스팅]에서 DI를 언제 왜 쓰는지, 써서 좋은점이 무엇인지, 아무 제약이 없이 적용할 수 있는지 등등.. 자세히 알아보자.
'Backend > Spring' 카테고리의 다른 글
@Autowired 빈 설정 방식 (+ @Qualifier, @Primary) (0) | 2023.12.22 |
---|---|
다양한 의존관계 주입 방법 (생성자 주입을 선택해야 하는 이유) (0) | 2023.12.18 |
스프링 빈 설정하는 방법 (XML, @Configuration, @Component) (1) | 2023.12.17 |
스프링의 싱글톤 (+ 싱글톤 레지스트리란?) (0) | 2023.12.11 |
DI (Dependency Injection, 의존관계 주입) 이란? (+ 필요성) (0) | 2023.12.10 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!