IOC? DI?

  • 스프링에서의 IoC(제어의 역전), DI(의존성 주입)은 사실상 같은 말입니다.
  • IoC란, 메소드나 객체의 호출 작업을 개발자가 하는것이 아닌 외부에서 처리하는 것을 말합니다. 즉, IoC 컨테이너에서 DI를 하게 됩니다.
  • 스프링의 IoC 컨테이너로는 ApplicationContext를 사용합니다.

 

ApplicationContext

  • 애플리케이션에서 IoC를 적용해서 관리할 모든 오브젝트에 대한 생성과 관계설정을 담당합니다.

 

… 어떻게?

빈을 생성해서 관리하는것 까진 알겠는데 빈에 달려있는 의존성은 어떻게 주입하는 건지 문득 궁금해졌습니다. A → B로 의존되어 있다면 빈 생성이 어떻게 이루어질까요? 다음과 같은 테스트 코드를 작성해 보겠습니다.

@Controller
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

}
@Service
@RequiredArgsConstructor
public class UserService {

    private final UserDao userDao;

    @PostConstruct
    public void construct() {
        System.out.println("UserService 생성 완료");
    }
}

아주 간단한 주입받는 테스트 코드입니다. 객체가 생성된 직후의 상황을 테스트하기 위해 @PostConstruct 어노테이션을 사용하였습니다.

저는 DI를 미션을 통해 리플렉션을 사용하여 직접 구현해 보았는데도 불구하고 아직도 어떻게 DI가 일어나는지 와닿지 않았습니다. 그렇다면 실제 주입 과정이 어떻게 일어나는지 디버그를 찍어보며 확인해 보았습니다. 참고로 생성자 주입의 경우입니다.

  1. AbstractBeanFactory의 getBean()을 통해 빈을 생성하려고 합니다. 이 때, 주입을 처리해야 하므로 다음 단계로 이동합니다.
  2. 싱글톤 빈이므로 싱글톤 빈 관련 로직이 수행되며 ConstructorResolver.autowireConstructor() 메서드를 사용하여 주입을 위해 사용할 생성자를 가져옵니다.
  3. DefaultListableBeanFactory.doResolveDependency() 메서드에서 descriptor을 통해 빈 이름을 가져오고, 가져온 빈 이름으로 빈 객체를 조회합니다.
    • descriptor : 주입되어야 하는 의존성에 대한 명세
    • descriptor.resolveCandidate() 메서드를 사용하여 주입받아야 하는 빈 이름을 넣어 다시한번 getBean() 메서드를 호출합니다. 빈이 만들어지지 않았다면 위의 내용이 반복됩니다.

생략된 내용이 많긴 하지만.. 디버깅을 찍어보면서 알게 된 내용은 여기까지입니다. 결론적으로 A → B → C 순으로 의존하고 있다면, 빈 C부터 만들어지고 마지막으로 빈 A가 만들어지는 것을 알 수 있었습니다.

+ Recent posts