자바 백엔드 입문 17편 — ApplicationContext 컨테이너 본체

2026-05-16자바 백엔드 입문

자바 백엔드 입문 17편. Spring 컨테이너의 본체 ApplicationContext가 정확히 무엇이고, BeanFactory와 어떻게 다르며 getBean·이벤트·국제화 같은 기능을 회사 인사 데이터베이스 비유로 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 17편 — ApplicationContext 컨테이너 본체

이 글은 자바 백엔드 입문 시리즈 59편 중 17편이에요. 16편에서 Bean이 도서관 책처럼 라이브러리 시스템에 등록·관리된다고 풀었다면, 이번 17편은 그 "라이브러리 시스템" 의 정체 — ApplicationContext를 들여다봅니다. Spring을 한 단어로 설명하라면 "ApplicationContext" 라고 답해도 될 만큼 핵심이에요.

ApplicationContext가 어렵게 들리는 이유

처음 "ApplicationContext" 라는 이름을 들으면 두 가지가 어색합니다.

첫째, 이름이 너무 추상적이에요. "Application의 Context?" — 한국말로 "애플리케이션의 맥락" 인데, 그게 뭘 의미하는지 잡히지 않아요.

둘째, BeanFactory라는 비슷한 이름이 또 있어요. 둘 다 "Bean을 관리하는 객체" 인데 어떻게 다른지 — 처음 보면 헷갈립니다.

이 글에서는 ApplicationContext를 회사 인사 데이터베이스 비유로 풀어 갑니다. 끝까지 따라오시면 "Spring을 한 단어로 설명하면 ApplicationContext" 가 한 번에 박혀요.

ApplicationContext = 회사 인사 데이터베이스

ApplicationContext는 Spring의 IoC 컨테이너 본체예요. 모든 Bean이 이 안에 등록되고, 의존성 관계도 이 안에서 풀리고, 객체 생성·소멸 모두 여기서 처리돼요.

회사 비유로 풀어볼게요. ApplicationContext는 회사 인사 데이터베이스예요. 정식 채용된 모든 직원(Bean)의 신상 정보·소속 부서·연락처·인사 카드(BeanDefinition)가 다 들어 있어요. 다른 부서에서 "개발팀의 김 과장 좀 연결해 줘" 요청하면 인사 DB가 김 과장 객체를 꺼내서 보내줍니다.

자바 코드로는 이렇게 생겨요.

ApplicationContext context = SpringApplication.run(MyApp.class, args);

// 컨테이너에서 Bean 꺼내기
HelloController controller = context.getBean(HelloController.class);
controller.hello();

SpringApplication.run() 의 반환값이 ApplicationContext 예요. 우리가 Spring Boot 메인 클래스를 짤 때 이 반환값을 안 받았을 뿐, 사실 모든 Spring Boot 앱은 ApplicationContext 한 개와 함께 돌아가요.

ApplicationContext가 하는 일 7가지

Spring 공식 문서에 따르면 ApplicationContext는 BeanFactory 기본 기능에 더해 다음 6가지를 추가로 합니다.

  1. Bean 관리 (BeanFactory에서 상속) — 객체 생성·의존성 주입·소멸
  2. AOP 통합 — 횡단 관심사(트랜잭션·로깅) 자동 처리 (17·18편)
  3. 메시지 리소스 처리 — 국제화(i18n) 지원. "안녕"·"Hello" 자동 분기
  4. 이벤트 발행 — 컨텍스트 안 Bean끼리 이벤트로 통신
  5. WebApplicationContext — 웹 환경 전용 서브 인터페이스 (HTTP 요청 컨텍스트)
  6. 환경 추상화 (Environment) — properties·profiles 관리. dev/prod 환경 분기
  7. Resource 추상화 — 파일·클래스패스·URL을 통일된 인터페이스로 다룸

이게 ApplicationContext를 "엔터프라이즈급" 컨테이너로 만드는 7가지 능력이에요. 회사 인사 DB가 단순히 직원 정보만 보관하는 게 아니라, 부서간 메시지 전달·다국어 게시판·환경별 권한 분기까지 다 처리하는 것과 같은 그림이에요.

ApplicationContext vs BeanFactory — 결정적 차이

여기서 입문자가 자주 헷갈리는 부분 — ApplicationContextBeanFactory가 어떻게 다른가.

구분BeanFactoryApplicationContext
위치하위 인터페이스 (기본)BeanFactory 상속 + 확장
Bean 생성 시점지연(Lazy) — 첫 호출 시즉시(Eager) — 시작 시 다 미리 만듦
국제화·이벤트·AOPXO
웹 환경 지원XWebApplicationContext로 확장
실무 사용거의 X거의 100%

쉽게 말하면 BeanFactory가 부모, ApplicationContext가 자식이며 훨씬 더 많은 일을 함. 실무에서는 거의 모든 Spring 앱이 ApplicationContext를 써요. BeanFactory 단독으로 쓰는 건 극히 제한된 메모리 환경(임베디드 IoT 같은)에서만 봐요.

여기서 시험 함정 자주 나와요. "BeanFactory가 ApplicationContext보다 기능이 많다" 가 보기로 나오면 X. ApplicationContext가 BeanFactory를 상속해 더 많은 기능을 제공해요. 부모-자식 관계가 정반대로 박힌 보기는 매번 함정.

ApplicationContext 구현체 3가지

ApplicationContext는 인터페이스이고, 실제로는 여러 구현체가 있어요. 어떤 설정 방식이냐에 따라 골라요.

// 1. Java Config 기반 (현대 표준)
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

// 2. XML 기반 (레거시)
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

// 3. 웹 환경
WebApplicationContext webCtx = ...; // Spring Boot가 자동 처리

신규 프로젝트는 거의 100% Java Config + AnnotationConfigApplicationContext 조합. Spring Boot도 내부적으로 이걸 쓰면서 "WebApplicationContext" 라는 웹 전용 래퍼를 자동으로 띄워줍니다. 우리는 SpringApplication.run() 한 줄만 호출하면 끝.

getBean — Bean을 꺼내는 두 가지 방식

ApplicationContext에서 Bean을 꺼내는 메서드 getBean(). 두 가지 방식이 있어요.

// 1. 타입으로 꺼내기 (권장)
HelloController c1 = context.getBean(HelloController.class);

// 2. 이름으로 꺼내기
HelloController c2 = context.getBean("helloController", HelloController.class);

타입 기반이 일반적으로 권장. 이름은 오타 위험이 있고 IDE가 검증 못 해주거든요. 다만 같은 타입의 Bean이 여러 개 있으면 어느 걸 꺼낼지 모호해서 이름을 명시해야 하는 경우가 있어요.

💡 실무에서 getBean 직접 호출 거의 없음

실무에서는 context.getBean() 을 직접 호출할 일이 거의 없어요. @Autowired 의존성 주입이 알아서 처리해주거든요. getBean()"의존성 주입이 어색한 일부 시나리오" 에서만 등장. 처음 배울 때 한 번 만나고, 이후엔 거의 안 마주칩니다.

ApplicationContext 시작 시 일어나는 일

SpringApplication.run() 한 줄 호출의 내부 흐름을 좀 더 정확히 들여다보면 이렇게 흘러요.

1. ApplicationContext 인스턴스 생성
2. @Configuration 클래스들 로드
3. @ComponentScan으로 클래스 패스 스캔
4. 발견한 @Component·@Service·@Repository·@Controller·@RestController로 BeanDefinition 생성
5. @Bean 메서드들로 추가 BeanDefinition 생성
6. BeanDefinition 등록 완료 후 Bean 생성 단계 시작
7. 각 Bean 생성 → 의존성 주입 → @PostConstruct 호출
8. ApplicationContext 준비 완료 (refresh 끝)
9. (웹 앱이면) 내장 Tomcat 시동 + 8080 포트 오픈
10. 종료 시 @PreDestroy 호출 + 컨테이너 닫기

이 10단계가 매 Spring Boot 시작 시 일어나요. 우리가 직접 코딩하는 건 거의 없어요. 그저 어노테이션 박힌 클래스를 짜두면 ApplicationContext가 알아서 다 처리합니다.

한 줄 정리 — ApplicationContext = Spring IoC 컨테이너의 본체. BeanFactory 기본 기능 + AOP·국제화·이벤트·환경·Resource 추상화. SpringApplication.run() 의 반환값이 바로 이거.

시험 직전 한 번 더 — ApplicationContext 입문자가 매번 헷갈리는 것

  • ApplicationContext = Spring IoC 컨테이너의 본체. Bean 보관소
  • 비유 = 회사 인사 데이터베이스. 직원(Bean) 등록·관리·연결
  • SpringApplication.run() 의 반환값이 ApplicationContext
  • BeanFactory = 부모 인터페이스. 가장 기본적인 Bean 관리
  • ApplicationContext = BeanFactory 상속 + 6가지 추가 기능
  • 추가 기능 = AOP / 국제화 / 이벤트 / 웹 / 환경 추상화 / Resource 추상화
  • BeanFactory는 Lazy 로딩, ApplicationContext는 Eager 로딩 (기본)
  • "BeanFactory가 더 많은 기능을 한다" 는 X — 정반대
  • 실무는 거의 100% ApplicationContext, BeanFactory 단독은 극히 제한된 환경
  • 구현체 3가지 = AnnotationConfigApplicationContext / ClassPathXmlApplicationContext / WebApplicationContext
  • 신규 프로젝트 = AnnotationConfigApplicationContext (Java Config)
  • Spring Boot = WebApplicationContext 자동 사용
  • getBean() 두 가지 = 타입 기반 / 이름 기반
  • 타입 기반이 권장 — 오타 위험 없음, IDE 검증 가능
  • 실무에서 getBean() 직접 호출 거의 없음 — @Autowired 가 대신 해줌
  • 컨테이너 시작 시 10단계 = 인스턴스 생성 → @Configuration 로드 → 컴포넌트 스캔 → BeanDefinition 등록 → Bean 생성 → DI → @PostConstruct → refresh 완료 → Tomcat 시동 → @PreDestroy 종료
  • @Configuration 클래스 = Java Config의 시작점 (13편)
  • @ComponentScan = 클래스 패스 자동 탐색 (12편)
  • context.getBeanDefinitionNames() = 등록된 모든 Bean 이름 목록
  • Spring Boot 한 앱에 보통 100~300개 Bean이 등록됨 (자동 Bean 포함)

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!