여기부터는 Spring을 이해하는 핵심 구간이다.
Reflection과 Class 객체를 이해했다면 이제 가장 많이 사용하는 문법인
@Service
@Repository
@Controller
@Autowired
@Transactional
이 실제로 어떻게 동작하는지 이해할 수 있다.
많은 사람들이 Annotation을
"설정을 편하게 해주는 문법"
정도로 알고 있지만, 실제로는 전혀 다르다.
Annotation은 아무 일도 하지 않는다.
이 사실을 이해하면 Spring 내부 구조가 한 번에 보이기 시작한다.
Annotation 동작 원리
"Annotation은 단순한 메타데이터이며, Reflection으로 읽는 프로그램이 있을 때만 의미가 생긴다."
Annotation은 그냥 표시일 뿐이다.
예를 들어
@Service
public class UserService {
}
를 보자.
많은 사람들이
@Service
↓
자동으로 객체 생성
이라고 생각한다.
하지만 실제로는 아니다.
Java 입장에서는
@Service
public class UserService {
}
와
public class UserService {
}
는 거의 동일하다.
둘 다 정상적으로 컴파일된다.
Annotation이 붙었다고 해서
객체 생성
메서드 실행
Bean 등록
DI 수행
같은 일은 절대로 일어나지 않는다.
Annotation의 정체
Annotation은
클래스나 메서드 등에 붙이는 추가 정보(Metadata) 이다.
예를 들어
@Service
public class UserService {
}
실제로 저장되는 의미는
UserService
추가 정보
----------------------
@Service
----------------------
정도이다.
메타데이터(Metadata)란?
메타데이터는
데이터를 설명하는 데이터
이다.
예를 들어
파일을 생각해보자.
photo.jpg
파일 크기 : 5MB
생성일 : 2025-01-01
작성자 : Kim
여기서
사진 자체가 데이터라면
파일 크기
생성일
작성자
는 메타데이터이다.
Annotation도 똑같다.
UserService 클래스
↓
추가 정보
↓
@Service
일 뿐이다.
그러면 누가 사용하는가?
바로 Reflection이다.
Spring은
패키지 스캔
↓
Class 객체 발견
↓
Reflection
↓
Annotation 확인
↓
@Service 발견
↓
Bean 생성
이라는 순서로 동작한다.
Reflection으로 Annotation 읽기
예제를 보자.
@Service
public class UserService {
}
Reflection 코드
Class<?> clazz = UserService.class;
boolean result =
clazz.isAnnotationPresent(Service.class);
System.out.println(result);
결과
true
이다.
Annotation 객체 자체도 가져올 수 있다.
Service service =
clazz.getAnnotation(Service.class);
이렇게 실제 Annotation 객체를 가져온다.
Annotation에도 값이 있다.
직접 Annotation을 만들어보자.
@interface MyComponent {
String value();
}
사용
@MyComponent("userService")
public class UserService {
}
Reflection
Class<?> clazz = UserService.class;
MyComponent annotation =
clazz.getAnnotation(MyComponent.class);
System.out.println(annotation.value());
결과
userService
이다.
직접 Annotation 만들어보기
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyService {
}
그리고
@MyService
public class UserService {
}
이렇게 사용할 수 있다.
그런데
여기까지 해도 아무 일도 일어나지 않는다.
왜냐하면
읽는 프로그램이 없기 때문
이다.
직접 Spring처럼 만들어보자.
Application Start
↓
클래스 목록 조회
↓
@MyService 확인
↓
객체 생성
↓
Map 저장
코드
Map<String, Object> beanContainer =
new HashMap<>();
Class<?> clazz = UserService.class;
if (clazz.isAnnotationPresent(MyService.class)) {
Object obj =
clazz.getDeclaredConstructor()
.newInstance();
beanContainer.put(
clazz.getSimpleName(),
obj
);
}
이제
@MyService
↓
Reflection 발견
↓
객체 생성
↓
Container 저장
이 된다.
사실 이것이
Spring IoC Container의 아주 축소된 형태이다.
Annotation에는 아무 로직도 없다.
많은 사람들이 착각하는 부분이다.
@Service
↓
객체 생성
이 아니라
실제로는
@Service
↓
Class 객체에 저장
↓
Reflection으로 읽음
↓
Spring이 해석
↓
객체 생성
이다.
Annotation이 실행되는 것이 아니다.
예를 들어
@Transactional
public void save() {
}
를 보자.
많은 사람들이
@Transactional
↓
트랜잭션 시작
이라고 생각한다.
실제로는
Spring
↓
Reflection
↓
@Transactional 발견
↓
Proxy 생성
↓
메서드 호출 전
↓
Transaction 시작
↓
메서드 실행
↓
commit / rollback
이다.
즉
@Transactional이 실행되는 것이 아니라
Spring이 Annotation을 보고 동작하는 것이다.
Annotation에도 생명주기가 있다.
Annotation은 언제까지 유지될지를 지정할 수 있다.
@Retention(RetentionPolicy.RUNTIME)
가장 많이 사용하는 옵션이다.
SOURCE
.java
↓
컴파일
↓
사라짐
대표
@Override
CLASS
.java
↓
.class
↓
저장
↓
실행 시 접근 불가
RUNTIME
.java
↓
.class
↓
JVM
↓
Reflection으로 읽기 가능
Spring은 대부분 이것을 사용한다.
Target도 지정할 수 있다.
@Target(ElementType.TYPE)
TYPE
클래스
@Target(ElementType.METHOD)
METHOD
메서드
@Target(ElementType.FIELD)
FIELD
필드
여러 개도 가능하다.
@Target({
ElementType.TYPE,
ElementType.METHOD
})
실제 Spring Annotation도 그렇다.
예를 들어
@Service
내부를 보면
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
}
거의 이런 형태이다.
생각보다 매우 단순하다.
전체 흐름
UserService.java
@Service
↓
컴파일
↓
.class 파일
↓
Annotation 정보 저장
↓
JVM 로딩
↓
Class 객체 생성
↓
Spring Reflection
↓
@Service 발견
↓
Bean 생성
↓
Container 등록
↓
@Autowired 주입
면접 포인트
Annotation이란?
클래스, 메서드, 필드 등에 부가 정보를 저장하는 메타데이터이다.
Annotation 자체가 동작하는가?
아니다. Annotation은 아무 로직도 수행하지 않으며 Reflection으로 읽는 프로그램이 있을 때만 의미를 가진다.
Spring에서 Annotation은 어떻게 동작하는가?
Spring이 Reflection으로 Class 객체를 조사하여 Annotation을 확인하고, 그 결과를 기반으로 Bean 생성, DI, AOP, Transaction 등의 기능을 수행한다.
다음 글 추천
다음은 Meta Annotation을 추천한다.
이 글을 보면
@Service가 사실은 @Component를 기반으로 만들어졌고,
Spring이 왜 새로운 Annotation을 쉽게 확장할 수 있는지까지 자연스럽게 이해할 수 있다.
'language > java' 카테고리의 다른 글
| Dynamic Proxy 원리 (0) | 2026.06.16 |
|---|---|
| Meta Annotation (0) | 2026.06.16 |
| Class 객체란? (0) | 2026.06.16 |
| Reflection 원리 (0) | 2026.06.16 |
| 번외편 - Java Comparator vs JavaScript sort() (0) | 2026.06.04 |
댓글