09c 지연로딩·N+1·해결 📚 전체 맵 10b 어노테이션 완전 정리
Series 10 · Bean·어노테이션 · 1/2

BEAN
LIFECYCLE
IoC

Bean 생명주기 · IoC 컨테이너 · @PostConstruct · @PreDestroy
Spring이 객체를 어떻게 만들고 관리하고 소멸시키는가

10a Bean 생명주기·IoC 10b 어노테이션 완전 정리
01~09 Java·Spring·JPA 10 Bean·어노테이션 11 Docker 12 용어사전·면접Q&A
이 파일의 학습 목적
10a — IoC 컨테이너 · Bean · 생명주기

Spring이 @Service @Repository가 붙은 클래스를 어떻게 인식하고, 왜 직접 new를 안 해도 되는지 — 이것이 IoC(제어의 역전)와 Bean이다. 10a는 Spring 컨테이너의 핵심 동작 원리를 정리한다.

이 파일에서 배울 것
  • IoC 컨테이너 — 객체 생성/관리 주체가 누구인가
  • Bean — Spring이 관리하는 객체의 정의
  • Bean 생명주기 — 생성→의존성 주입→사용→소멸
  • @PostConstruct / @PreDestroy
  • 싱글톤 스코프 — Bean이 하나만 존재하는 이유
프로젝트 코드 연결
  • · @Service @Repository @Component → 자동 Bean 등록
  • · AppConfig.java @Bean — 1차 수동 Bean 등록
  • · @RequiredArgsConstructor → 생성자 주입 자동화
  • · Bean 스코프 — 싱글톤이 기본인 이유
시리즈 순서: 09 JPA 완전 이해 → 10a ← 지금 여기 → 10b 어노테이션 완전정복
01 — IoC 컨테이너
객체 생성·관리를 Spring이 맡는다 — 개발자가 new 하지 않아도 되는 이유
🏭 IoC — Inversion of Control (제어의 역전) IoC
🏢 비유 — 회사 인사팀
내가 직접 직원 채용·관리·해고 = 직접 new 하고 관리
인사팀(Spring IoC 컨테이너)이 채용·배치·관리·해고 담당
→ 나는 "UserService 직원 필요해요" 라고만 하면 됨
→ Spring이 알아서 만들어서 줌 (의존성 주입)
❌ IoC 없이
public class UserController {
private UserService service =
new UserService();
// 직접 생성 → 강한 결합
// UserService 바뀌면
// Controller도 수정해야 함
}
✅ IoC 사용
@RequiredArgsConstructor
public class UserController {
private final UserService service;
// Spring이 주입해줌
// 느슨한 결합
// 테스트 시 교체 가능
}
💡 ApplicationContext = IoC 컨테이너 구현체
Spring Boot 시작 시 ApplicationContext 생성
@Component, @Service, @Repository, @Controller 붙은 클래스 스캔
→ Bean 객체 생성 및 등록 → 의존관계 주입 → 애플리케이션 실행
02 — Bean이란?
Spring IoC 컨테이너가 관리하는 객체 — 싱글턴이 기본
Bean = Spring이 관리하는 객체 Bean
🏪 비유 — 편의점 재고
편의점(IoC 컨테이너) = 물건(Bean)을 미리 준비해서 보관
손님이 "콜라 주세요" → 창고에서 꺼내서 줌 (같은 콜라, 싱글턴)
→ Bean은 기본적으로 싱글턴 — 애플리케이션 전체에서 인스턴스 1개만 존재
Java — Bean 등록 방법 3가지
// 1. @Component 계열 — 클래스에 직접 붙임 (자동 등록)
@Component // 범용
@Service // 비즈니스 로직 계층
@Repository // DB 접근 계층
@Controller // 웹 컨트롤러 계층
public class UserService { ... }

// 2. @Bean — @Configuration 클래스 안에서 수동 등록
@Configuration
public class AppConfig {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
// → passwordEncoder Bean이 컨테이너에 등록됨
// → 다른 곳에서 @Autowired / 생성자 주입으로 사용 가능

// 3. @SpringBootApplication — 시작점에서 자동 컴포넌트 스캔
@SpringBootApplication // 이 패키지 하위 모두 스캔
public class BoardApplication {
public static void main(String[] args) {
SpringApplication.run(BoardApplication.class, args);
}
}
💡 싱글턴 Bean — 주의할 점
Bean은 인스턴스 1개 → 여러 요청이 동시에 같은 Bean 사용
Bean 내부에 상태(인스턴스 변수)를 저장하면 안 됨 → 다른 요청과 데이터 섞임
→ Service, Repository는 상태 없이 메서드만 → 안전
03 — Bean 생명주기
생성 → 의존성 주입 → 초기화 → 사용 → 소멸 — 각 단계에서 할 수 있는 것
🔄 Spring Bean 생명주기 전체 흐름 Lifecycle
1
스프링 컨테이너 생성
ApplicationContext 초기화 — Bean 정의 정보 로딩
2
Bean 객체 생성 (new)
생성자 호출 — @Component 붙은 클래스 인스턴스 생성
3
의존성 주입 (DI)
생성자 주입 / @Autowired 필드 주입 완료 — 다른 Bean 연결
4
초기화 콜백 — @PostConstruct
의존성 주입 완료 직후 호출 — DB 연결 확인, 캐시 초기화, 설정 검증 등
5
Bean 사용
애플리케이션 실행 중 — 요청 처리, 비즈니스 로직 수행
6
소멸 전 콜백 — @PreDestroy
컨테이너 종료 직전 호출 — DB 연결 닫기, 리소스 정리
7
Bean 소멸
스프링 컨테이너 종료 — 모든 Bean GC 대상
04 — @PostConstruct · @PreDestroy
Bean 초기화·소멸 시점에 코드 실행 — 가장 많이 쓰는 생명주기 훅
🔔 생명주기 콜백 어노테이션 Callback
Java — @PostConstruct / @PreDestroy 실제 사용
@Component
public class DataInitializer {

private final UserRepository userRepository;

@PostConstruct
// Bean 생성 + 의존성 주입 완료 직후 자동 호출
public void init() {
// 앱 시작 시 관리자 계정 없으면 자동 생성
if (!userRepository.existsByUsername("admin")) {
User admin = new User("admin", "ROLE_ADMIN");
userRepository.save(admin);
// System.out.println("관리자 계정 생성됨");
}
}

@PreDestroy
// 컨테이너 종료 직전 자동 호출
public void destroy() {
// 리소스 정리, 연결 닫기 등
// System.out.println("앱 종료 전 정리 작업");
}
}
어노테이션호출 시점주요 사용 목적
@PostConstructBean 생성 + DI 완료 직후초기 데이터 설정, 연결 확인, 캐시 워밍업
@PreDestroy컨테이너 종료 직전DB 연결 닫기, 파일 저장, 리소스 반납
⚠️ 생성자에서 하면 안 되는 초기화 작업
생성자 실행 시점 = 의존성 주입 전 → 주입된 Bean이 아직 null
@PostConstruct = DI 완료 후 → 주입된 Bean 모두 사용 가능
→ DB 조회, Repository 사용 등은 반드시 @PostConstruct에서
05 — Bean 스코프
싱글턴이 기본 — 필요 시 프로토타입·요청 스코프 사용
📦 @Scope — Bean 인스턴스 범위 Scope
스코프인스턴스 생성 시점사용 사례
singleton컨테이너 시작 시 1개 (기본값)Service, Repository, Controller 대부분
prototype요청할 때마다 새 인스턴스상태를 가져야 하는 객체
requestHTTP 요청당 1개웹 환경 — 요청별 상태 관리
sessionHTTP 세션당 1개웹 환경 — 세션별 상태 관리
Java — 스코프 설정
// 기본 — 싱글턴 (생략 가능)
@Component
@Scope("singleton")
public class UserService { ... }

// 프로토타입 — 매번 새 인스턴스
@Component
@Scope("prototype")
public class TempProcessor { ... }
// → 주입받을 때마다 new TempProcessor() 호출
💡 우리 프로젝트는 거의 전부 싱글턴
UserService, BoardService, UserRepository, BoardController 등
→ 모두 상태(인스턴스 변수) 없이 메서드만 → 싱글턴 안전
→ 로컬 변수(메서드 내부)는 요청마다 새로 생성 → 공유 안 됨
09c 지연로딩·N+1·해결 📚 전체 맵 10b 어노테이션 완전 정리