ApplicationContext 또는 BeanFactory(이 둘 중 하나 사용, 난 context 사용)
BeanFactory - 사실상 IoC 컨테이너
Application Context - Bean Factory 상속받음(그러므로 같은 일 한다고 볼 수 O, 그러나 그 외 다양한 일들 한다.)
IoC 컨테이너는 Bean을 만들고 그 사이 의존성을 엮어준다. 또한 그 Bean들을 제공해준다.(Bean이기 때문에 컨테이너 속에 있는 것이겠지?)
OwnerController, OwnerRepository, PetController, PetRepository 모두 컨테이너 안 Bean으로 등록되어 있다. (모든 객체가 Bean으로 등록되는 것이 아님, intellij 왼쪽 녹색 콩 표시 확인)
private final ApplicationContext applicationContext;
public OwnerController(OwnerRepository clinicService, ApplicationContext applicationContext){
this.owners = clinicService; // 알아서 주입
this.applicationContext = applicationContext; // 사실 알아서 주입해주기 때문에 이렇게 직접 주입해줄 필요가 없대
}
@GetMappling("/bean")
@ResponseBody
public String bean(){
// 이렇게 하면 밑의 문자열 자체가 응답의 본문이 된다. (문자열은 애플리케이션 컨텍스트가 담고있던 오너 컨트롤러 인스턴스의 해시값)
return "bean: " + applicationContext.getBean(OwnerController.class); // getBean 직접 하지 않고 바로 onwers(OwnerRepository)를 사용하면 된다.
}
Controller가 Repository를 사용 중, 이 때!! 생성자에서 주입하는 repository는 바로 IoC 컨테이너(applicationContext)가 Bean을 찾아서 넣어준다.
(주의)
의존성 주입은 Bean끼리만 가능 = IoC 컨테이너 안 객체들끼리만 의존성 주입 가능, 밖에 있는 객체는 의존성 주입 X
@Autowired
ApplicationContext applicationContext;
@Test
public void getBean(){
// ioc 컨테이너 내부의 빈들을 모두 가져올 수 있다.
applicationContext.getBeanDefinitionNames();
// 일반적 방법 new()
OwnerController ownerController = new OwnerController();
// 이미 오너컨트롤러의 빈을 가져온다.
OwnerController bean = applicationContext.getBean(OwnerController.class);
assertThat(bean).isNotNull();
}
우리가 실제로 IoC 컨테이너를 사용하기 어렵지만, ControllerTest에서 임의로 사용 가능
new()해서 가져온 OwnerController나 applicationContext.getBean()해서 가져온 OwnerController나 둘 다 같은 인스턴스이다.
싱글톤 객체 - 어떤 인스턴스 하나를 애플리케이션 전반에서 계속해서 재사용하는 것, 매번 새로 만들지 X
특히 멀티스레드 상황에서 싱글톤 객체를 구현하는 것 자체는 번거롭고 조심스러운 일이다. 그런 일을 IoC 컨테이너를 사용하면 손쉽게(소스코드에 특별한 코드를 넣지 않아도) 컨테이너에 등록되어있는 빈을 가져다 써서 싱글톤 객체 가능하다.