어노테이션은 코드 요소에 메타데이터를 추가하여, 코드의 동작을 설명하거나 처리할 정보를 제공하는 특별한 타입의 인터페이스이다.
1. 어노테이션이란?
어노테이션(Annotation)은 Java에서 코드에 메타데이터를 추가하는 방법으로, 클래스, 메서드, 필드 등 다양한 코드 요소에 추가적인 정보를 제공한다. 어노테이션은 주로 컴파일러나 런타임 환경에서 처리되며, 코드의 동작에 영향을 미치거나, 문서화 및 검사 등을 위한 목적으로 사용된다. 예를 들어,
@Override, @Deprecated와 같은 기본 어노테이션 외에도 개발자가 정의한 어노테이션을 통해 동적 처리를 할 수 있다.2. 주요 메타어노테이션
@Retention- 해당 어노테이션이 어떤 시점까지 유효한지를 지정하는 메타 어노테이션이다. 이 메타 어노테이션은 어노테이션이 소스 코드, 컴파일 타임, 런타임까지 살아있는지 정의한다.
- 종류
RetentionPolicy.SOURCE: 어노테이션이 컴파일러에서만 존재하고, 컴파일된 바이트코드에는 포함되지 않고 주로 코드 분석 도구나 IDE에서만 사용된다.RetentionPolicy.CLASS: 기본값으로, 어노테이션이 클래스 파일에 포함되지만, JVM에서 런타임 동안에는 접근할 수 없다.RetentionPolicy.RUNTIME: 어노테이션이 런타임까지 유지되어, 리플렉션을 통해 런타임에 어노테이션을 읽을 수 있다.
@Target- 어노테이션이 어디에 적용될 수 있는지를 지정한다. 예를 들어, 클래스, 메서드, 필드 등에 어노테이션을 적용할 수 있다. 이 메타 어노테이션을 사용하여 어노테이션의 적용 대상을 제한할 수 있다.
- 종류
ElementType.TYPE: 클래스, 인터페이스, 열거형ElementType.FIELD: 필드(변수)ElementType.METHOD: 메서드ElementType.PARAMETER: 매개변수ElementType.CONSTRUCTOR: 생성자ElementType.LOCAL_VARIABLE: 지역 변수ElementType.ANNOTATION_TYPE: 다른 어노테이션ElementType.PACKAGE: 패키지
@Documented- 해당 어노테이션이 JavaDocs에 포함되도록 한다. 이 메타 어노테이션을 사용하면, 해당 어노테이션을 적용한 코드가 문서화될 때 JavaDocs에 포함된다.
@Inherited- 클래스에만 적용되며, 상속된 클래스에 어노테이션을 자동으로 상속하도록 지정한다. 부모 클래스에 적용된 어노테이션이 자식 클래스에서 자동으로 인식될 수 있도록 한다.
@Repeatable- 해당 어노테이션이 여러 번 적용될 수 있도록 허용하는 메타 어노테이션이다. 컨테이너 어노테이션과 함께 사용되며, 컨테이너 어노테이션은 반복된 어노테이션을 배열로 감싸는 역할을 한다.
3. 예제 코드
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value();
}public class Router {
UserController userController;
public Router(UserController userController) {
this.userController = userController;
}
public void routing(String path) {
// 1. 메서드 찾아내기
Method[] methods = userController.getClass().getMethods();
// 2. 어노테이션 체크하기
for (Method method : methods) {
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
if (requestMapping == null) continue;
// 3. value와 path 일치 확인해서 일치하면 invoke 하기
if (requestMapping.value().equals(path)) {
try {
method.invoke(userController);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("메서드 실행중 오류가 발생했어요.");
}
}
}
}
}public class UserController {
@RequestMapping("/login")
public void login() {
System.out.println("로그인");
}
@RequestMapping("/join")
public void join() {
System.out.println("회원가입");
}
@RequestMapping(value = "/logout")
public void logout() {
System.out.println("로그아웃");
}
}public class App {
public static void main(String[] args) {
Router router = new Router(new UserController());
Scanner scanner = new Scanner(System.in);
String path = scanner.nextLine();
router.routing(path);
}
}4. 정리
RequestMapping어노테이션 인터페이스@Target(ElementType.METHOD)를 통해 메서드에만 적용될 수 있도록 정의된다.@Retention(RetentionPolicy.RUNTIME)을 통해 어노테이션이 런타임에 읽힐 수 있도록 정의된다.String value()를 경로를 인자로 받아, 해당 경로와 매칭되는 메서드를 지정한다.
Router클래스UserController객체를 받아, 경로에 맞는 메서드를 호출하는 역할을 한다.routing()메서드에서 리플렉션을 사용하여UserController클래스의 메서드들을methods배열에 넣는다.getAnnotation()메서드를 통해RequestMapping어노테이션을 찾고, 경로(value)와 일치하는 메서드를 실행한다.
UserController클래스- 각 메서드에
@RequestMapping어노테이션을 사용하여 해당 메서드가 처리할 경로를 지정한다.
App클래스scanner를 통해 사용자로부터 경로를 입력받고, 입력된 경로에 맞는 메서드를 실행한다.
Share article