
자바 개발을 하다 보면 클래스나 메서드 위에 @Override, @Transactional, @RestController와 같은 코드들을 자주 접하게 됩니다. 단순한 주석처럼 보이지만, 이들은 현대 자바 프레임워크(Spring, Hibernate 등)의 근간을 이루는 어노테이션(Annotation)입니다. 본 글에서는 어노테이션의 본질적인 개념부터 런타임에 어떻게 동작하는지, 그리고 커스텀 어노테이션을 만드는 방법까지 심도 있게 다루어 보겠습니다.
1. 어노테이션(Annotation)이란 무엇인가?
어노테이션은 자바 5(JDK 1.5)부터 도입된 기능으로, 코드에 추가하는 '메타데이터(Metadata)'를 의미합니다. 메타데이터란 '데이터에 대한 데이터', 즉 코드 자체의 로직에는 직접적인 영향을 주지 않으면서 해당 코드가 어떻게 처리되어야 하는지 컴파일러나 런타임 환경에 정보를 제공하는 역할을 합니다. 과거에는 설정 정보를 주로 XML 파일에 관리했으나, 프로젝트 규모가 커짐에 따라 코드와 설정의 불일치 문제가 발생했습니다. 어노테이션은 이러한 설정 정보를 소스코드에 직접 결합하여 코드의 가독성을 높이고 유지보수를 용이하게 만듭니다.
2. 어노테이션의 분류와 생명주기
어노테이션은 사용 용도와 유지되는 시점에 따라 다음과 같이 분류할 수 있습니다.
| 분류 | 주요 어노테이션 | 설명 |
|---|---|---|
| 표준 어노테이션 | @Override, @Deprecated, @SuppressWarnings | 자바 컴파일러에게 정보를 전달하기 위한 기본 어노테이션 |
| 메타 어노테이션 | @Target, @Retention, @Documented, @Inherited | 어노테이션을 정의하기 위한 어노테이션 |
| 커스텀 어노테이션 | 개발자가 정의한 @MyAnnotation 등 | 특정 비즈니스 로직이나 프레임워크 기능을 수행하기 위해 정의 |
어노테이션의 유지 정책 (Retention Policy)
어노테이션이 언제까지 살아있느냐를 결정하는 것은 매우 중요합니다.
- SOURCE: 소스 파일에만 존재하며 컴파일 시점에 제거됩니다. (예: @Override)
- CLASS: 클래스 파일까지는 남지만, JVM 로드 시점에 제거됩니다. (기본값)
- RUNTIME: 실행 시점(Runtime)에도 유지되어 리플렉션(Reflection)을 통해 정보를 읽을 수 있습니다.
3. 어노테이션은 어떻게 작동하는가?
많은 개발자가 오해하는 부분 중 하나는 어노테이션 자체가 능동적인 동작을 수행한다고 생각하는 것입니다. 하지만 어노테이션은 그저 표식일 뿐입니다. 실제 동작은 어노테이션 정보를 읽어 처리하는 프로세서(Processor)가 담당합니다.
- 컴파일 시점: APT(Annotation Processing Tool)가 소스 코드를 스캔하여 특정 어노테이션을 발견하면 새로운 코드를 생성하거나 체크를 수행합니다. (예: Lombok의 @Data)
- 런타임 시점: 프로그램 실행 중 리플렉션 API를 사용하여 클래스, 메서드, 필드에 붙은 어노테이션 정보를 읽고, 그에 맞는 비즈니스 로직을 수행합니다. (예: Spring의 의존성 주입)
4. 실무 예제: 커스텀 어노테이션 만들기
특정 메서드의 실행 시간을 측정하는 간단한 커스텀 어노테이션 예제를 작성해 보겠습니다.
// 1. 어노테이션 정의
@Target(ElementType.METHOD) // 메서드에 사용 가능
@Retention(RetentionPolicy.RUNTIME) // 실행 시점에 리플렉션으로 읽음
public @interface Timer {
}
// 2. 어노테이션 적용
public class MyService {
@Timer
public void heavyTask() {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("작업 완료");
}
}
// 3. 프로세서 구현 (리플렉션 활용)
public class TimerProcessor {
public void process(Object obj) throws Exception {
Method[] methods = obj.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Timer.class)) {
long start = System.currentTimeMillis();
method.invoke(obj); // 메서드 실행
long end = System.currentTimeMillis();
System.out.println(method.getName() + " 소요시간: " + (end - start) + "ms");
}
}
}
}
5. 어노테이션의 장점과 한계
| 장점 | 한계 및 주의사항 |
|---|---|
|
|
6. 마무리하며
자바 어노테이션은 단순한 주석을 넘어, 선언적 프로그래밍을 가능케 하는 강력한 도구입니다. 어노테이션의 작동 원리를 이해하면 스프링과 같은 거대 프레임워크가 어떻게 마법처럼 동작하는지 파악할 수 있으며, 나아가 자신만의 효율적인 라이브러리를 구축할 수 있는 발판이 됩니다. 무분별한 사용보다는 런타임 성능과 코드 가독성 사이의 균형을 고려하며 사용하는 지혜가 필요합니다.
내용 출처:
- Oracle Java Language Specification: Annotations
- Baeldung: A Guide to Java Annotations
- Modern Java in Action (Raoul-Gabriel Urma)
'Language > Java' 카테고리의 다른 글
| [JAVA] 나만의 문법을 창조하다 : 자바 커스텀 어노테이션 설계 및 구현 가이드 (0) | 2026.01.21 |
|---|---|
| [JAVA] 자바 리플렉션(Reflection)의 심층 이해와 실무 활용 전략 (0) | 2026.01.21 |
| [JAVA] 쓰레드 로컬(ThreadLocal)의 마법 : 쓰레드별 독립적인 데이터 관리 (0) | 2026.01.21 |
| [JAVA] 비동기 프로그래밍의 완성 : Callable과 Future 인터페이스 심층 분석 (0) | 2026.01.21 |
| [JAVA] 자바 성능 최적화의 열쇠 : 쓰레드 풀(Thread Pool)과 ExecutorService 완벽 가이드 (0) | 2026.01.21 |