코드와 함께 보는 DI와 IoC

김경민·2026년 3월 27일
post-thumbnail

서론

저는 스프링 프레임워크를 배우면서 가장 먼저 IoC와 DI라는 개념에 대해서 접했습니다. IoC와 DI는 설명만 들었을 때는 정말 추상적인 개념이기도 하고 저도 배우면서 정확한 동작에 대해 설명해주는 게시물이 없어서 이 글을 쓰게 됐습니다.
이 포스트에서는 제가 어떤 방식으로 이 개념들을 이해 했고, IoC와 DI를 코드 레벨에서 어떤 방식으로 구현했는지 알아보도록 하겠습니다.

Bean이란?

Bean은 IoC 컨테이너에서 관리되는 인스턴스를 Bean이라고 합니다. Bean의 메타데이터는 BeanDefinition에서 관리 되고 있습니다.
다음은 BeanDefinition의 구현체인 AbstractBeanDefinition의 코드 중 일부입니다.

사진에서 제시된 첫 번째 필드인 beanClass는 어떤 클래스로 Bean을 만들 것인가에 대한 정보를 담고 있습니다.

다음에 설명할 BeanFactoryBeanDefinition을 관리하고 Bean을 생성하는 역할을 합니다.

BeanFactory란?

시작하기에 앞서 우리는 BeanFactory가 뭔지에 대해서 알아야 합니다. BeanFactory는 빈을 생성하고 관리하는 핵심 인터페이스입니다.

BeanFactory의 구현체 중에 하나인 DefaultListableBeanFactory는 여러 빈을 String, BeanDefinition과 함께 담아서 ConcurrentHashMap 으로 저장하고 있습니다. 우리가 실제로 사용하는 @Component를 가진 클래스 들이 모두 여기에서 저장되고 관리되고 있는 것 입니다.

그렇다면 인스턴스가 저장되는 위치는?

참고로 실제로 new 키워드를 통해 생성된 인스턴스는 DefaultSingletonBeanRegistry에서 singletonObjects에 따로 저장되고 있습니다.

Application Context란?

ApplicationContext는 IoC 컨테이너의 구현체 중 하나로, BeanFactory를 확장하여 실무에서 표준으로 사용되는 컨테이너입니다. ListableBeanFactory를 확장하여 여러 Bean을 관리할 수 있게 합니다.

ListableBeanFactory를 상속함으로 Bean의 관리를 하고 있습니다.
BeanFactory와 다른점은 ApplicationContext는 다국어 메시지 처리, 이벤트 발행/구독, 리소스 로딩 등의 작업을 추가로 한다는 것 입니다.

DI

이제 Spring의 ApplicationContext가 작동하기 위한 클래스를 모두 간단하게 알아봤으니 DI가 어떤 방식으로 작동하는지 알아보도록 하겠습니다.
di의 동작을 테스트 해보기 위해서 코드를 작성했습니다.

	@Test
	void di_component_방식_생성자_주입_검증() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		context.register(ComponentAccountRepository.class, ComponentAccountService.class, ComponentUserService.class); // context.register()로 개별 등록
		context.refresh();

		AccountService accountService = context.getBean(AccountService.class);

		assertThat(accountService).isNotNull();
		assertThat(accountService.getAccount(1L)).isEqualTo("component-account-1");
	}

ApplicationContext에서 스캔할 대상을 지정하기 위해서 context.register()를 활용해서 스캔 대상으로 넣고, AccountServicecontext.getBean()을 하고 그 빈이 제대로 등록되었는지 확인하는 간단한 테스트 입니다.


AnnotatedBeanDefinitionReader의 해당 메소드에서 어떻게 인식된 객체가 BeanDefinition 형태로 저장되는 것 또한 보실 수 있습니다.

그 후에 마지막 줄에는 결과적으로 BeanRegistry에 저장되어 인스턴스로 관리되는 모습입니다.

참고 자료

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
https://www.baeldung.com/spring-application-context
https://github.com/spring-projects/spring-framework

0개의 댓글