Inversion of Control. 말 그대로 제어의 역전이다. 프로그램 제어 흐름의 주도권을 외부로 넘겨주는 것이다.
Dependency Injection. 의존 관계 주입은 IoC를 구현하는 방법중 가장 대중화된 방법론중 하나이며, 객체가 필요한 종속성을 외부에서 주입해주는 것이다.
우선 Spring Docs에서 Ioc는 DI로도 알려져 있다고 소개하고 있는만큼 편의를 위해 IoC=DI라고 작성하겠다.
DI를 이해하기 위해선 의존성 이라는 것을 이해해야한다.
의존 단어 그대로 '어떠한 일을 자신의 힘으로 하지 못하고 다른 어떤 것의 도움을 받는 것'을 의존이라고 한다.
코드에서 이런 의존성은 다음과 같이 확인할 수 있다.
public class Consumer {
void eat() {
Chicken chicken = new Chicken();
chicken.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat();
}
}
class Chicken {
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
위 코드를 보면 Consumer클래스에서 eat()을 실행하면, 해당 메소드를 실행하고 chicken클래스의 eat()을 실행하게 된다. 만약 위 코드에서 chicken이 없다면? Consumer는 혼자서 아무것도 할 수 없다. 심지어 피자가 먹고 싶다면 consumer.eat()의 내부 코드를 수정해야하는 대참사가 벌어지게 된다. 이런 형태를 강한 의존성 이라고 할 수 있다.
그렇다면 위 상태에서 의존성을 약하게 하고싶다면? Interface를 사용하면 될 것이다.
public class Consumer {
void eat(Food food) {
food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat(new Chicken());
consumer.eat(new Pizza());
}
}
interface Food {
void eat();
}
class Chicken implements Food{
@Override
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
class Pizza implements Food{
@Override
public void eat() {
System.out.println("피자를 먹는다.");
}
}
위 코드를 보면 consumer가 먹고싶은 매뉴를 new ~()를 통해 바로바로 사용하는 걸 볼 수 있다. 이런 형태를 약한 결합, 약한 의존성이라고 할 수 있다.
주입 또한 말 그대로 '흘러 들어가도록 쏟아서 넣는 것'이다.
주입은 총 3개의 방식으로 나눌 수 있다.
Consumer consumer = new Consumer();
consumer.food = new Chicken();
위 코드 처럼 클래스의 필드에 다이렉트로 주입한다.
이 방법은 사실 필드는 대부분 private로 닫히기 때문에 사용하진 않는다.
Consumer consumer = new Consumer();
consumer.setFood(new Chicken());
set~메소드를 통해서 Chicken 객체를 주입하고 있다. 이 방식도 나쁘지 않지만 다음 방식을 많이 사용한다.
Consumer consumer = new Consumer(new Chicken());
Consumer 객체를 인스턴스화 할때. 생성자를 통해서 주입하는 방식이다. 이 방식을 가장 많이 사용하고 선호한다. 다만, 이 역시 속한 그룹 by 그룹이므로, 모든 방법을 알고있어야한다.
처음 강한 의존성을 지닌 코드를 보면 Consumer 내부에서 Food 객체를 생성해서 사용했다. 이런 경우 제어의 흐름을 Consumer -> Food라고 할 수 있다.
이후 Food 객체를 생성해서 Consumer에게 전달하는 방식 (주입 시리즈)로 변경하면서 Consumer 내부 코드는 수정없이 생성자 파라미터 등만 변경하면 어느 Food가 들어오든 전부 먹을 수 있게 되었다. 이런 흐름을 Food -> Consumer라고 할 수 있으며, 결국 흐름이 역전되었기 때문에 제어의 역전. 즉 IOC라고 할 수 있다.
하지만 아직 애매하기 때문에 Spring은 IoC를 위해 IoC컨테이너를 지원하고 있다.