class A {
B b = new B();
}
A가 B를 사용
"의존대상 B가 변하면, 그것이 A에 영향을 미친다."
B의 기능이 추가 또는 변경될 때, A에 영향을 미치는 경우 A가 B에 의존한다.
객체가 의존객체를 직접 생성해서 사용하는게 아니라, 의존관계를 객체 외부에서 결정하고 주입해서 사용하는 것
프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IoC)이라 한다. 구현 객체는 자신의 로직을 실행하는 역할만 담당한다. 프로그램의 제어 흐 름은 AppConfig가 가져간다.
순환참조
스프링 컨테이너는 A 클래스의 빈을 생성하기위해 B 클래스의 빈을 주입해줘야 한다. 따라서 B 클래스의 빈을 찾을 것이다. 근데 B 클래스의 빈이 없으니까 B 클래스의 빈을 생성하려 하니 A 클래스의 빈이 필요해서A 클래스의 빈을 생성하려 하고 무한 반복에 빠지게 된다.
ApplicationContext를 스프링 컨테이너라 한다. @Configuration이 붙은 클래스를 구성 정보로 사용한다. 여기서 @Bean이 붙은 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. (스프링 컨테이너 생성->스프링 빈 등록->의존관계 설정)
스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
스프링 컨테이너에 등록된 객체.
빈 이름은 메서드 이름.
싱글톤 방식의 주의점
진짜 공유필드는 조심해야 한다! 스프링 빈은 항상 무상태(stateless)로 설계하자.
컴포넌트 스캔&의존관계 자동 주입
@ComponentScan을 설정 클래스에 붙인다. -> @Component 애노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다.
-> 생성자에 @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.
컴포넌트 스캔 기본 대상
스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
초기화 콜백: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출 -> @PostConstruct
소멸전 콜백: 빈이 소멸되기 직전에 호출 -> @PreDestroy