F-LAB JAVA · 5주차 · Phase 8 · Spring 컨테이너
🌱 Phase 8 시작 — 5주차 마지막 Phase, Spring 컨테이너 실체
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
빈 (Bean) 은 Spring 컨테이너가 생성·관리하는 객체이고, BeanFactory 는 빈을 생성·관리하는 기본 인터페이스이며, ApplicationContext 는 BeanFactory 를 확장해 부가 기능 (i18n·이벤트 등) 을 더한 실무 표준 컨테이너다.
빈 은 일반 자바 객체 중 Spring 컨테이너가 관리하는 것으로, 직접new하지 않고 컨테이너가 생성·주입·관리한다.
BeanFactory 는 빈을 생성하고 의존성을 주입하며 제공 (getBean) 하는 가장 기본적인 컨테이너 인터페이스다.
ApplicationContext 는 BeanFactory 를 상속·확장하여 국제화 (i18n), 이벤트 발행, 리소스 로딩, AOP 등 부가 기능을 더한 것으로, 실무에서 표준으로 쓰인다.
빈은@Configuration클래스 안의@Bean메서드로 정의하며 이때 메서드 이름이 빈의 ID (이름) 가 되고,@Component+ 컴포넌트 스캔으로도 등록할 수 있다.
빈 / BeanFactory / ApplicationContext = 창고/공장:
빈 (Bean):
- 창고가 관리하는 부품
- 직접 안 만들고 창고가 보관
- 필요하면 창고에서 받음
BeanFactory (기본 창고):
- 부품 보관·제공
- 기본 기능
- "부품 주세요" (getBean)
ApplicationContext (스마트 공장):
- 기본 창고 + α
- 부품 제공 (창고 기능)
- + 다국어 안내 (i18n)
- + 알림 (이벤트)
- + 자동화 (AOP)
- 실무 표준
@Bean 메서드 이름 = 부품 라벨:
- 메서드 이름 = 빈 ID
- "shipmentDao" 라벨로 찾음
→ 빈 = 컨테이너 관리 객체, BeanFactory(기본) → ApplicationContext(확장, 실무).
1. 빈(Bean)이란
2. BeanFactory
3. ApplicationContext (확장)
4. @Configuration / @Bean
5. @Bean 메서드 이름 = 빈 ID
6. ApplicationContext 추가 기능
7. 빈 등록 방식 (컴포넌트 스캔)
8. 컨테이너와 빈
9. 면접 + 자기 점검
빈 (Bean):
Spring 컨테이너가
생성·관리하는 객체.
- new 직접 X
- 컨테이너가 생성
- 컨테이너가 관리
일반 객체 vs 빈:
일반 객체:
- new 로 생성
- 내가 관리
빈:
- 컨테이너 생성
- 컨테이너 관리
- DI 대상
빈 특징:
- 컨테이너 관리
- 기본 싱글톤 (Unit 8.3)
- DI 받음/제공
- 생명주기 관리
// 빈 (Spring 관리 객체)
@Repository // 빈 등록
public class ShipmentDao {
// Spring 이 생성·관리
}
@Service // 빈 등록
public class ShipmentService {
private final ShipmentDao shipmentDao; // 빈 주입
public ShipmentService(ShipmentDao dao) {
this.shipmentDao = dao; // 컨테이너가 주입
}
}
// ShipmentDao, ShipmentService = 빈
// new 안 함, 컨테이너가 생성·주입
빈 (Bean) 이란 무엇인가?
답:
1. 빈:
차이:
특징:
관리:
BeanFactory:
빈을 생성·관리하는
가장 기본적인 인터페이스.
- 빈 생성
- DI
- getBean 제공
BeanFactory 기본 기능:
- getBean(name/type)
- 빈 생성 (요청 시, lazy)
- 의존성 주입
- 싱글톤 관리
지연 로딩 (Lazy):
BeanFactory:
- 빈 요청 시 생성
- getBean 호출 시
→ 메모리 효율 (필요 시)
→ 하지만 오류 늦게 발견
// BeanFactory 인터페이스 (개념)
public interface BeanFactory {
Object getBean(String name);
<T> T getBean(Class<T> requiredType);
boolean containsBean(String name);
// ...
}
// 빈 제공 계약
// BeanFactory 사용 (기본)
public class BeanFactoryExample {
public void use() {
// BeanFactory (지연 로딩)
// DefaultListableBeanFactory factory = ...;
// ShipmentDao dao = factory.getBean(ShipmentDao.class);
// → 이때 생성 (lazy)
// 실무는 ApplicationContext (다음)
}
}
// BeanFactory: 기본 컨테이너
// 실무: ApplicationContext (확장)
BeanFactory의 역할은?
답:
1. BeanFactory:
기능:
지연 로딩:
인터페이스:
ApplicationContext:
BeanFactory 를 확장한
실무 표준 컨테이너.
- BeanFactory 기능 +
- 부가 기능
BeanFactory 확장:
ApplicationContext extends BeanFactory:
- 빈 생성·DI (상속)
- + 부가 기능
→ 상위 호환
추가 기능:
- 국제화 (i18n)
- 이벤트 발행
- 리소스 로딩
- AOP
- 환경 (프로파일)
즉시 로딩 (Eager):
ApplicationContext:
- 시작 시 싱글톤 빈 생성
- 미리 (eager)
→ 시작 시 오류 발견
→ 실무 선호
// ApplicationContext 구현체들
// 1. 애노테이션 기반
ApplicationContext ctx1 =
new AnnotationConfigApplicationContext(AppConfig.class);
// 2. XML 기반
// ApplicationContext ctx2 =
// new ClassPathXmlApplicationContext("beans.xml");
// 3. Spring Boot (자동)
// SpringApplication.run(App.class, args);
// ApplicationContext (ILIC)
@Configuration
public class IlicConfig {
@Bean
public ConnectionMaker connectionMaker() {
return new CustomerAConnectionMaker();
}
@Bean
public ShipmentDao shipmentDao() {
return new ShipmentDao(connectionMaker());
}
}
public class IlicApp {
public static void main(String[] args) {
// ApplicationContext (실무 표준)
ApplicationContext ctx =
new AnnotationConfigApplicationContext(IlicConfig.class);
// 빈 사용
ShipmentDao dao = ctx.getBean(ShipmentDao.class);
// 시작 시 빈 미리 생성 (eager)
// + i18n, 이벤트 등 부가 기능 가능
}
}
class ShipmentDao { ShipmentDao(ConnectionMaker cm) {} }
interface ConnectionMaker { Connection makeConnection(); }
class CustomerAConnectionMaker implements ConnectionMaker {
public Connection makeConnection() { return null; }
}
ApplicationContext가 BeanFactory 확장인 이유는?
답:
1. ApplicationContext:
확장:
추가:
즉시 로딩:
// @Configuration + @Bean
@Configuration
public class AppConfig {
@Bean
public ConnectionMaker connectionMaker() {
return new NConnectionMaker(); // 빈 정의
}
@Bean
public ShipmentDao shipmentDao() {
return new ShipmentDao(connectionMaker()); // 의존성
}
}
@Configuration:
설정 클래스 표시:
- 빈 정의 모음
- 컨테이너가 읽음
→ 자바 기반 설정
@Bean:
메서드가 빈 생성:
- 반환 객체 = 빈
- 컨테이너가 호출
- 결과 등록
→ 빈 정의 메서드
XML vs 자바 설정:
XML (전통):
<bean id="dao" class="...">
자바 설정 (현대):
@Bean
public Dao dao() { ... }
→ 타입 안전, 리팩토링 용이 (자바)
// ILIC 자바 설정
@Configuration
public class IlicConfig {
@Bean
public ConnectionMaker connectionMaker() {
return new CustomerAConnectionMaker();
}
@Bean
public ShipmentDao shipmentDao() {
return new ShipmentDao(connectionMaker()); // 의존성 연결
}
@Bean
public BookingDao bookingDao() {
return new BookingDao(connectionMaker()); // 같은 연결 재사용
}
@Bean
public ShipmentService shipmentService() {
return new ShipmentService(shipmentDao()); // 서비스 조립
}
}
// 컨테이너가 이 설정 읽고 빈 생성·연결
class ShipmentDao { ShipmentDao(ConnectionMaker cm) {} }
class BookingDao { BookingDao(ConnectionMaker cm) {} }
class ShipmentService { ShipmentService(ShipmentDao dao) {} }
interface ConnectionMaker { Connection makeConnection(); }
class CustomerAConnectionMaker implements ConnectionMaker {
public Connection makeConnection() { return null; }
}
@Configuration / @Bean으로 빈 정의는?
답:
1. @Configuration:
@Bean:
자바 설정:
vs XML:
@Configuration
public class AppConfig {
@Bean
public ShipmentDao shipmentDao() { // 메서드 이름 = 빈 ID
return new ShipmentDao();
}
}
// 빈 ID = "shipmentDao"
// ctx.getBean("shipmentDao")
기본 규칙:
@Bean 메서드 이름:
- 빈의 ID (이름)
- 기본값
shipmentDao() → "shipmentDao"
// 이름 명시 지정
@Bean(name = "customDao")
public ShipmentDao shipmentDao() {
return new ShipmentDao();
}
// 빈 ID = "customDao" (메서드 이름 무시)
// ID 로 빈 조회
ApplicationContext ctx = ...;
// 메서드 이름으로
ShipmentDao dao = (ShipmentDao) ctx.getBean("shipmentDao");
// 타입으로 (더 권장)
ShipmentDao dao2 = ctx.getBean(ShipmentDao.class);
@Configuration
public class IlicConfig {
// 메서드 이름 = 빈 ID
@Bean
public ShipmentDao shipmentDao() { // ID: "shipmentDao"
return new ShipmentDao(connectionMaker());
}
@Bean
public ConnectionMaker connectionMaker() { // ID: "connectionMaker"
return new CustomerAConnectionMaker();
}
// 이름 지정
@Bean(name = "primaryConnection")
public ConnectionMaker mainConnection() { // ID: "primaryConnection"
return new CustomerAConnectionMaker();
}
}
// 조회
// ctx.getBean("shipmentDao") // 메서드 이름
// ctx.getBean("primaryConnection") // 지정 이름
// ctx.getBean(ShipmentDao.class) // 타입 (권장)
class ShipmentDao { ShipmentDao(ConnectionMaker cm) {} }
interface ConnectionMaker { Connection makeConnection(); }
class CustomerAConnectionMaker implements ConnectionMaker {
public Connection makeConnection() { return null; }
}
@Bean 메서드 이름 = 빈 ID인가?
답:
1. 기본:
규칙:
지정:
조회:
ApplicationContext 추가 기능:
1. 국제화 (i18n)
2. 이벤트 발행/구독
3. 리소스 로딩
4. 환경/프로파일
5. AOP
// 국제화 (MessageSource)
@Autowired
private MessageSource messageSource;
public String getMessage(Locale locale) {
return messageSource.getMessage(
"shipment.created", null, locale);
// 언어별 메시지
}
// ILIC Vue 3 i18n 과 연계 (백엔드 메시지)
// 이벤트 발행/구독
@Component
public class ShipmentEventPublisher {
private final ApplicationEventPublisher publisher;
public void publish(Shipment s) {
publisher.publishEvent(new ShipmentCreatedEvent(s.getId()));
}
}
@EventListener
public void onCreated(ShipmentCreatedEvent e) {
// 구독 (컨테이너가 호출)
}
record ShipmentCreatedEvent(Long id) {}
// 리소스 로딩
@Autowired
private ResourceLoader resourceLoader;
public void loadConfig() {
Resource resource = resourceLoader.getResource(
"classpath:freight-rates.json");
// 파일/클래스패스/URL 통합
}
// ApplicationContext 부가 기능 활용 (ILIC)
@Service
public class ShipmentService {
private final MessageSource messageSource; // i18n
private final ApplicationEventPublisher publisher; // 이벤트
public ShipmentService(MessageSource ms,
ApplicationEventPublisher pub) {
this.messageSource = ms;
this.publisher = pub;
}
public void createShipment(Shipment shipment, Locale locale) {
// 비즈니스
save(shipment);
// i18n 메시지
String msg = messageSource.getMessage(
"shipment.created", null, locale);
// 이벤트 발행 (4주차 audit 시스템 연계)
publisher.publishEvent(new ShipmentCreatedEvent(shipment.getId()));
}
private void save(Shipment s) { }
}
record ShipmentCreatedEvent(Long id) {}
// ApplicationContext 가 i18n, 이벤트 등 제공
ApplicationContext의 추가 기능은?
답:
1. 추가 기능:
i18n:
이벤트:
리소스:
빈 등록 방식:
1. @Bean (자바 설정)
2. @Component 스캔
3. XML (전통)
// 컴포넌트 스캔
@Configuration
@ComponentScan("com.ilic") // 패키지 스캔
public class AppConfig { }
// 스캔 대상 (@Component 계열)
@Component // 일반
@Service // 서비스
@Repository // DAO
@Controller // 컨트롤러
스테레오타입 애노테이션:
@Component: 일반 빈
@Service: 비즈니스 계층
@Repository: 데이터 계층 (예외 변환)
@Controller: 표현 계층
→ 모두 @Component 기반
@Bean vs @Component:
@Bean:
- 메서드 (설정 클래스)
- 외부 라이브러리 빈
- 세밀한 제어
@Component:
- 클래스 (스캔)
- 내 클래스
- 간편
// 컴포넌트 스캔 (ILIC)
@Configuration
@ComponentScan("com.ilic")
public class IlicConfig {
// 외부 라이브러리는 @Bean
@Bean
public ConnectionMaker connectionMaker() {
return new CustomerAConnectionMaker();
}
}
// 내 클래스는 @Component 계열 (자동 스캔)
@Repository
public class ShipmentDao {
private final ConnectionMaker connectionMaker;
public ShipmentDao(ConnectionMaker cm) {
this.connectionMaker = cm;
}
}
@Service
public class ShipmentService {
private final ShipmentDao shipmentDao;
public ShipmentService(ShipmentDao dao) {
this.shipmentDao = dao;
}
}
@RestController
public class ShipmentController {
private final ShipmentService service;
public ShipmentController(ShipmentService service) {
this.service = service;
}
}
// 스캔으로 자동 등록 + 의존성 주입
interface ConnectionMaker { Connection makeConnection(); }
class CustomerAConnectionMaker implements ConnectionMaker {
public Connection makeConnection() { return null; }
}
컴포넌트 스캔이란?
답:
1. 등록 방식:
스캔:
스테레오타입:
@Bean vs @Component:
컨테이너와 빈:
컨테이너:
- 빈 생성·관리
- 빈 보유
빈:
- 컨테이너 안에서
- 관리됨
빈 등록 흐름:
1. 설정 읽기 (@Bean/@Component)
2. 빈 정의 등록
3. 빈 생성
4. 의존성 주입
5. 빈 저장 (컨테이너)
6. getBean 제공
빈 컨테이너 내부 (개념):
Map<String, Object> beans:
- "shipmentDao" → 인스턴스
- "connectionMaker" → 인스턴스
- ...
→ ID 로 관리
빈 라이프사이클:
생성 → 의존성 주입
→ @PostConstruct
→ 사용
→ @PreDestroy → 소멸
컨테이너가 관리
// 컨테이너와 빈 관계
@Component
public class ShipmentDao {
@PostConstruct
public void init() {
// 컨테이너가 생성·주입 후 호출
log.info("ShipmentDao 빈 초기화");
}
@PreDestroy
public void destroy() {
// 컨테이너 종료 시
log.info("ShipmentDao 빈 소멸");
}
}
// 컨테이너:
// 1. ShipmentDao 빈 생성
// 2. 의존성 주입
// 3. init() 호출
// 4. Map 에 보관 ("shipmentDao" → 인스턴스)
// 5. 요청 시 제공
// 6. 종료 시 destroy() 호출
컨테이너와 빈의 관계는?
답:
1. 관계:
등록 흐름:
내부:
라이프사이클:
| Q | 핵심 답변 |
|---|---|
| 빈? | 컨테이너 관리 객체 |
| BeanFactory? | 빈 생성·관리 기본 |
| ApplicationContext? | BeanFactory 확장 (부가) |
| @Configuration/@Bean? | 자바 설정 |
| @Bean 이름? | 메서드 이름 = 빈 ID |
| 추가 기능? | i18n, 이벤트, AOP |
| 등록 방식? | @Bean, 스캔, XML |
| 컴포넌트 스캔? | @ComponentScan |
| 컨테이너-빈? | 생성·관리 |
| @Bean vs @Component? | 외부 vs 내 클래스 |
답:
답:
답:
답:
답:
1. 빈과 컨테이너
2. 빈 정의
3. ApplicationContext 부가 기능
이번 Unit에서 빈 팩토리/ApplicationContext 를 봤다면, 다음은 getBean() 동작.
🌱 Phase 8 — Spring 컨테이너
✅ Unit 8.1 빈 팩토리와 ApplicationContext ← 여기
⏭ Unit 8.2 getBean()의 동작
⏭ Unit 8.3 싱글톤 레지스트리 ★깊이
⏭ Unit 8.4 의존관계 주입 DI ★깊이 (+ 졸업 시험)
✅ Part A — 동시성 마무리 (7 Unit)
🌱 Part B — 토비의 스프링
✅ Phase 3~7 (15 Unit)
🌱 Phase 8 — Spring 컨테이너 (1/4 진행)
총: 23/26 Unit
🌱 Phase 8 시작 — Spring 컨테이너