제어의 역전
의존관계에 대한 책임을 제3자에게 위임 (책임에 대한 분리)
객체지향적으로 Single Responsibility Principle(단일 책임 원칙)을 지킬 수 있음
예시
1) B Interface를 구현한 B1, B2 Class가 있음
2) A는 B의 Method를 사용하고자 함
3) A Class에서 직접 호출
3-1) Factory Class에서 호출 후 B의 정보를 읽어와 주입
의존성 주입
Spring에서 IoC 역할을 하는 모듈을 Spring Container, DI Container라고 부름
구체적인 의존 객체와 그것을 사용하는 주체인 클라이언트 객체를 런타임 시 연결
결합도가 낮은 코드를 작성할 수 있고, 변경이 자유로움 (다양한 확장 방법 가능)
조건
1) 클래스 모델이나 코드는 인터페이스에만 의존 (런타임 시점의 의존 관계가 드러나지 않는다.)
2) 런타임 시점의 의존관계는 Factory나 Container와 같은 제3의 존재에 의해 결정
3) 의존관계는 사용할 객체에 대한 레퍼런스를 외부에서 제공(매개변수 등)해줌으로써 만들어짐
// DI 위반
// 구체적인 클래스의 존재를 A Class가 이미 알고 있음
public class A {
private B b;
public A() {
b = new B_1();
}
}
// DI 충족
// 객체에 대한 레퍼런스를 외부에서 제공하는 식으로 코드를 작성
// A Class는 런타임 시점에 전달받은 인자(b)와의 의존관계 형성
public class A {
private B b;
public A(B b) { // B1 or B2 Class의 객체가 DI Container를 통해 주입될 예정
this.b = b;
}
}
Spring IoC는 일반적인 IoC 개념에 DI의 개념을 추가한 IoC/DI Container
Spring의 Bean Factory를 이용하여 작성한 IoC 방법
/*
* @Configuration: Bean Factory가 사용할 설정정보(Component Scan을 통해 Bean으로 생성)
* @Bean: return되는 Object를 Bean으로 생성
*/
@Configuration
public class Factory {
@Bean
public A a() {
return new A();
}
@Bean(name="b_1")
public B b_1() {
return new B_1();
}
@Bean(name="b_2")
public B b_2() {
return new B_2();
}
}
// Client단
// ApplicationContext.getBean을 통해 Bean 객체를 받아서 a 변수에 주입
// getBean을 호출함으로써 객체가 생성되고 Spring Container의 Singleton으로 등록
// [Singleton]
// 해당 Bean이 한번도 사용되지 않아 생성되어 있지 않다면 Bean을 생성하고,
// 한번이라도 사용되어진 Bean이라면 생성된 Bean Object를 바로 사용한다.
public class Test {
private A a;
// [ApplicationContext 객체는 Bean 설정 방식에 따라 가져오는 방식이 다름](https://it-mesung.tistory.com/28)
// 위의 경우엔 java를 활용하여 Bean을 등록 (Factory 클래스가 설정 파일이 됨)
ApplicationContext context = new AnnotationConfigApplicationContext(Factory.class);
a = (A) context.getBean('a'); //Bean 이름으로 가져오기
a = (A) context.getBean(A.class); //Class로 가져오기
}
```