
'사용하는 객체'를 A 클래스라고 하고 '사용되는 객체'를 B 클래스라고 한다.
A 클래스에서 B 클래스를 사용하려면 new 키워드를 이용해 B 클래스의 인스턴스를 생성하고 B 클래스의 메서드를 사용하게 된다. 이때 B 클래스에서 구현했던 메서드를 변경하면 그 영향으로 A 클래스에서도 해당 메서드를 변경해야 된다. 이런 관계를 'A 클래스는 B 클래스에 의존한다'라고 한다.
의존에는 다음 두 가지 유형이 있다.
'사용하는 객체'인 A 클래스에서 '사용되는 객체'인 B 클래스의 methodX 메서드를 호출하는 경우를 예로 들어보면

이때 설계가 변경돼서 '사용되는 객체'를 새롭게 생성된 C 클래스로 변경하고 methodY 메서드를 호출하도록 변경해야 한다면 3 군데를 수정해야 한다.
B b=new B(); -> C c=new C();
b.methodX-> c.methodY;
methodX()-> methodY()
수정할 부분이 적으면 문제 없지만 많다면 수정 작업과 수정에 의한 동작 테스트에 많은 시간이 할애된다.
I 인터페이스가 있고 그것을 구현한 '사용되는 객체'인 B클래스가 있다. '사용하는 객체'인 A 클래스에서 B 클래스의 methodX 메서드를 호출한다.
주의할 점은 A 클래스에서는 인터페이스로 추상화된 I를 이용한다는 것이다.

여기서도 설계 변경이 발생해서 '사용되는 객체' 클래스를 변경하게 되면
이번에는 I i=new B(); -> I i=new C();로 바꿔주기만 하면 된다.
이러한 이점 때문에 클래스 의존보다 인터페이스 의존을 사용하는 것으로 수정할 곳을 줄일 수 있다.





여기서 AddCalc를 SubCalc로 바꾸려면 Call 클래스의 import를 수정하거나 추가하고, new SubCalc()로 바꿔주면 된다.


'사용되는 객체' 클래스를 변경할 때는 '사용하는 객체' 클래스에서 세 곳을 변경해야 했고, 인터페이스 의존으로 작성했을 때는 한 곳만 수정하면 된다. 하지만 '의존성 주입'을 사용하면 '사용하는 객체'의 클래스를 수정하지 않아도 된다.
의존성 주입은 '의존하는 부분을 외부에서 주입하는 것'이다.
지금까지는 인스턴스를 생성할 때 new 키워드를 사용했지만 인스턴스 생성과 같은 작업을 DI 컨테이너가 할 수 있다.
즉, 임의로 구현한 클래스를 인스턴스로 만들어주는 기능이 제공된다.
의존하는 부분에 인터페이스를 이용한다는 것이다.
인스턴스 생성에 new 키워드를 사용하지 않는다는 것이다.
정리하면 인스턴스를 생성하고자 하는 클래스에 인스턴스 생성 어노테이션을 부여한다는 것이다.
표식이라고 이해하면 편하다.
스프링 프레임워크는 시작할 때 대상 프로젝트의 모든 패키지를 스캔하는데 이를 컴포넌트 스캔(Component Scan)이라고 한다.
이때 인스턴스 생성 어노테이션이 부여된 클래스를 추출해서 해당 클래스의 인스턴스를 생성한다.
스프링 프레임워크에 의해 생성된 인스턴스를 이용하는 클래스에 참조를 받는 필드를 선언하고 필드에 @Autowired 어노테이션을 부여한다.