어노테이션 개념 & 커스텀 어노테이션¶
PHASE 2 | Java 핵심 — 객체지향
키워드:@,어노테이션,메타데이터,@Target,@Retention,리플렉션,커스텀 어노테이션,RUNTIME
어노테이션이란?¶
코드에 붙이는 메타데이터. @로 시작하며, 코드 자체의 동작은 바꾸지 않고 부가 정보를 제공한다.
메타데이터란?¶
데이터에 대한 데이터, 즉 코드 자체가 아니라 코드에 대한 부가 정보다.
사진 파일 = 데이터
사진의 촬영 날짜, 위치, 카메라 기종 = 메타데이터
코드(메서드) = 데이터
@Override = 메타데이터 ("이 메서드는 오버라이딩이다"라는 부가 정보)
어노테이션의 3가지 용도¶
| 용도 | 예시 | 동작 시점 |
|---|---|---|
| 컴파일러 검사 | @Override, @Deprecated |
컴파일 시점 |
| 코드 자동 생성 | @Getter, @Builder (Lombok) |
컴파일 시 코드 생성 |
| 런타임 동작 | @Transactional, @Autowired |
실행 시점 (리플렉션) |
자주 쓰는 Java 기본 어노테이션¶
@Override // 오버라이딩 검증 (부모 메서드 없으면 컴파일 에러)
@Deprecated // 더 이상 사용하지 않는 코드 표시
@SuppressWarnings("unchecked") // 컴파일 경고 억제
커스텀 어노테이션 만들기¶
@Target — 어디에 붙일 수 있는지¶
ElementType.METHOD // 메서드
ElementType.TYPE // 클래스, 인터페이스
ElementType.FIELD // 필드
ElementType.PARAMETER // 파라미터
@Retention — 언제까지 유지되는지¶
| 값 | 유지 시점 | 용도 |
|---|---|---|
SOURCE |
컴파일 전까지 | @Override |
CLASS |
.class 파일까지 | 거의 안 씀 |
RUNTIME |
실행 시점까지 | Spring 어노테이션 대부분 |
Spring 어노테이션 대부분이
RUNTIME인 이유:
실행 시점에 리플렉션으로 어노테이션을 읽어서 동작하기 때문이다.
SOURCE나CLASS면 실행 시점에 어노테이션 정보가 사라져서 Spring이 읽을 수 없다.
어노테이션의 동작 원리¶
어노테이션 자체는 표시만 한다. 실제 동작은 어노테이션을 읽는 코드가 따로 있다.
어노테이션 = 표시
리플렉션 = 그 표시를 읽는 도구
실제 동작 = 표시를 읽고 처리하는 별도 코드 (인터셉터, AOP 등)
리플렉션이란?¶
실행 시점에 클래스, 메서드, 필드 정보를 읽고 조작하는 기능이다.
Spring이 @Autowired, @Transactional 같은 어노테이션을 실행 시점에 읽고 동작하는 게 전부 리플렉션 덕분이다.
커스텀 어노테이션 실무 예시¶
어노테이션 단독으로는 아무 동작도 안 한다¶
반드시 그걸 읽고 처리하는 코드(인터셉터, AOP 등)가 같이 있어야 한다.
// 1. 어노테이션 정의 (표시만)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired { }
// 2. 동작 코드 정의 (인터셉터에서 어노테이션 읽고 처리)
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 리플렉션으로 어노테이션 있는지 확인
LoginRequired annotation =
handlerMethod.getMethodAnnotation(LoginRequired.class);
if (annotation == null) {
return true; // 어노테이션 없으면 그냥 통과
}
// 어노테이션 있으면 로그인 체크
String token = request.getHeader("Authorization");
if (token == null) {
response.setStatus(401);
return false;
}
return true;
}
}
// 3. 사용 - 붙이기만 하면 자동으로 처리됨
@LoginRequired
@GetMapping("/mypage")
public String myPage() { ... }
왜 메서드 직접 호출 대신 어노테이션을 쓰나?¶
// 메서드 방식 - 매번 직접 호출, 까먹으면 누락
@GetMapping("/mypage")
public String myPage() {
loginCheck(); // 매번 직접 호출해야 함
...
}
// 어노테이션 방식 - 붙이기만 하면 자동 처리
@LoginRequired
@GetMapping("/mypage")
public String myPage() { ... }
커스텀 어노테이션을 쓰는 핵심 이유:
공통 로직을 자동으로 처리해서 중복 코드를 없애고, 누락 실수를 방지하기 위해.
런타임 어노테이션을 읽는 방법¶
어노테이션을 읽고 처리하는 코드가 어디 있느냐는 용도에 따라 다르다.
| 용도 | 읽는 방법 |
|---|---|
| HTTP 요청 앞에서 처리 (로그인, 권한) | 인터셉터 |
| 메서드 실행 전후 처리 (트랜잭션, 로깅) | AOP |
| 그 외 커스텀 처리 | 직접 리플렉션 |
인터셉터는 PHASE 8 Spring MVC, AOP는 PHASE 7 Spring Core에서 자세히 다룬다.
면접 포인트¶
Q. 어노테이션이란 무엇인가요?
코드에 붙이는 메타데이터로, 컴파일 시점 검사, 코드 자동 생성, 런타임 동작 등 다양한 용도로 사용된다.
Q. @Retention(RUNTIME)이 왜 필요한가요?
Spring이 실행 시점에 리플렉션으로 어노테이션을 읽어서 동작하기 때문이다.
SOURCE나 CLASS면 실행 시점에 어노테이션 정보가 사라져서 Spring이 읽을 수 없다.
Q. 커스텀 어노테이션을 왜 사용하나요?
공통 로직을 자동으로 처리해서 중복 코드를 없애고 누락 실수를 방지하기 위해 사용한다.
어노테이션 자체는 표시만 하고, 인터셉터나 AOP가 그 표시를 읽고 실제 동작을 처리한다.