이 챕터에서는 Reflection → Bean 생성 → DI → Proxy → AOP → Transaction 순서가 가장 자연스럽다.
그래서 이번 글은 단순히
"Bean은 Spring이 관리하는 객체입니다."
수준으로 끝나면 안 된다.
독자가
Spring Boot를 실행하면 내부에서 실제로 무슨 일이 일어나는가?
를 머릿속으로 그릴 수 있어야 한다.
Bean 생성 과정
Spring Boot가 실행되면 내부에서는 무슨 일이 일어날까?
이전 글에서는
Reflection을 이용해서
@Service
public class UserService {
}
를 발견하고
객체를 생성한 뒤
DI를 수행한다는 것을 배웠다.
하지만 실제 Spring 내부는 훨씬 복잡하다.
Spring은 단순히
new UserService();
를 실행하는 것이 아니라,
수많은 단계를 거쳐 하나의 Bean을 생성한다.
이번 글에서는
Spring Boot가 시작되는 순간부터 Bean이 완성될 때까지의 전체 흐름을 살펴보자.
먼저 Bean이란?
많은 사람들이
Bean = Spring이 관리하는 객체
라고 외운다.
맞는 말이다.
하지만 조금 더 정확하게 말하면
Spring IoC Container(ApplicationContext)가 생성하고, 관리하고, 생명주기를 제어하는 객체
이다.
예를 들어
@Service
public class UserService {
}
우리는
new UserService();
를 작성하지 않는다.
대신
Spring이
ApplicationContext
↓
UserService 생성
↓
관리
↓
필요한 곳에 주입
을 수행한다.
Spring Boot 시작
가장 처음 실행되는 코드는
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(
Application.class,
args
);
}
}
이다.
여기서
SpringApplication.run(...)
한 줄이
수많은 작업을 수행한다.
간단히 표현하면
Application Start
↓
ApplicationContext 생성
↓
Bean 등록
↓
Bean 생성
↓
DI 수행
↓
Application Ready
이다.
1단계
Component Scan
먼저
@SpringBootApplication
을 확인한다.
실제로는
@SpringBootApplication
↓
@ComponentScan
↓
@Component
@Service
@Repository
@Controller
탐색
이 수행된다.
프로젝트를 스캔하면서
UserService.class
OrderService.class
UserController.class
를 찾는다.
2단계
BeanDefinition 생성
여기서 아직 객체를 만들지 않는다.
대신
객체의 설계도만 만든다.
예를 들어
@Service
public class UserService {
}
Spring 내부
BeanDefinition
------------------------
Class
Scope
Lazy 여부
생성 방식
생성자 정보
------------------------
를 생성한다.
즉,
객체
X
----------------
객체를 만들기 위한 정보
O
이다.
BeanDefinition이 필요한 이유
Spring은
모든 객체를 한 번에 만들지 않는다.
먼저
UserService
OrderService
ProductService
UserController
의
정보를 모두 수집한다.
그리고
의존 관계를 분석한다.
예를 들어
@Service
public class OrderService {
private final UserService userService;
}
Spring은
OrderService
↓
UserService 필요
를 먼저 알게 된다.
3단계
Bean 생성
이제 Reflection으로
객체를 생성한다.
Constructor<?> constructor =
clazz.getDeclaredConstructor();
constructor.newInstance();
즉,
Reflection
↓
Constructor 조회
↓
newInstance()
↓
Bean 생성
이다.
4단계
DI(Dependency Injection)
객체를 만들었다고 끝이 아니다.
다음 클래스를 보자.
@Service
public class OrderService {
private final UserService userService;
}
Spring은
Bean Container에서
UserService를 찾는다.
BeanContainer
------------------------
UserService
OrderService
------------------------
그리고
new OrderService(userService);
를 Reflection으로 수행한다.
5단계
BeanPostProcessor
많은 사람들이 모르는 단계이다.
Bean 생성
↓
DI 완료
↓
BeanPostProcessor 실행
여기서
Spring은
Bean을 수정하거나
Proxy로 교체할 수 있다.
예를 들어
@Transactional
public void save() {
}
Spring은
UserService
↓
Transaction Proxy
↓
Bean Container 저장
으로 변경한다.
즉,
Container 안에는
실제 객체가 아니라
Proxy가 들어갈 수도 있다.
그림으로 보면
Bean 생성
↓
UserService
↓
BeanPostProcessor
↓
@Transactional 발견
↓
Transaction Proxy 생성
↓
Bean Container 저장
6단계
Singleton Cache 저장
기본적으로
Spring Bean은 Singleton이다.
즉,
BeanContainer
------------------------
UserService
OrderService
ProductService
------------------------
하나만 생성된다.
Controller
@Autowired
UserService userService;
Service
@Autowired
UserService userService;
둘 다
같은 객체를 사용한다.
실제 흐름
Application 시작
Application Start
↓
@ComponentScan
↓
BeanDefinition 생성
↓
Reflection으로 객체 생성
↓
DI 수행
↓
BeanPostProcessor
↓
Proxy 생성(필요 시)
↓
Singleton Cache 저장
↓
Application Ready
왜 BeanDefinition이 먼저 필요할까?
예를 들어
@Service
class A {
private B b;
}
@Service
class B {
private A a;
}
Spring이
바로 생성한다면
A 생성
↓
B 필요
↓
B 생성
↓
A 필요
↓
무한 반복
이 된다.
BeanDefinition으로
전체 구조를 먼저 분석하기 때문에
순서를 결정할 수 있다.
Bean 생성은 언제 일어날까?
기본적으로
Singleton Bean은
Application Start
↓
즉시 생성(Eager Loading)
된다.
하지만
@Lazy
@Service
public class UserService {
}
라면
Application Start
↓
생성 안 함
↓
처음 사용할 때 생성
된다.
실무에서 가장 많이 보는 Bean
Controller
↓
Service
↓
Repository
↓
Configuration
↓
Component
모두 Bean이다.
Bean Factory와 ApplicationContext
실제로는
BeanFactory
↓
ApplicationContext
구조이다.
BeanFactory
객체 생성
기능만 가진다.
ApplicationContext
BeanFactory
+
이벤트
+
국제화
+
AOP
+
환경설정
을 포함한다.
그래서
실무에서는 거의 항상
ApplicationContext
를 사용한다.
그림으로 전체 정리
Application Start
│
▼
@ComponentScan
│
▼
BeanDefinition 생성
│
▼
Reflection 객체 생성
│
▼
DI 수행
│
▼
BeanPostProcessor
│
▼
@Transactional 발견
│
▼
Proxy 생성
│
▼
Singleton Cache 저장
│
▼
Application Ready
Reflection과 연결해서 보면
이전 글에서
Reflection은
Spring이 클래스를 이해하는 눈(Eye)
이라고 했다.
이번 글에서는
Reflection이
Bean 생성
↓
DI 수행
↓
BeanPostProcessor
↓
Proxy 생성
까지 이어지는 것을 확인했다.
즉,
Reflection은
Spring Bean 생명주기의 시작점이다.
면접 포인트
Bean이란?
Spring IoC Container(ApplicationContext)가 생성하고 관리하는 객체이다.
Bean 생성 과정
Component Scan
↓
BeanDefinition 생성
↓
Reflection 객체 생성
↓
Dependency Injection
↓
BeanPostProcessor
↓
Proxy 생성
↓
Singleton Cache 저장
BeanDefinition이 필요한 이유는?
객체를 생성하기 전에 Bean의 메타데이터와 의존 관계를 먼저 분석하기 위해서이다.
BeanPostProcessor는 무엇인가?
Bean 생성 이후 Bean을 수정하거나 Proxy로 교체할 수 있는 확장 포인트이며, @Transactional, @Async, @Cacheable, AOP 등이 이 과정을 활용한다.
다음 글 추천
다음은 객체 생명주기와 Spring Bean이다.
이 글에서는
new
↓
생성자
↓
DI
↓
@PostConstruct
↓
사용
↓
@PreDestroy
↓
소멸
뿐만 아니라,
- InitializingBean
- DisposableBean
- BeanPostProcessor와 실행 순서
- Singleton / Prototype / Request Scope의 생명주기 차이
까지 연결하면 Spring의 전체 흐름이 완성된다.
'language > java' 카테고리의 다른 글
| Dynamic Proxy와 Spring AOP (0) | 2026.06.17 |
|---|---|
| 객체 생명주기와 Spring Bean (0) | 2026.06.17 |
| Reflection과 Spring DI (0) | 2026.06.17 |
| Virtual Thread(Java 21) (0) | 2026.06.17 |
| Stream 개선사항(Java 9~21) (0) | 2026.06.17 |
댓글