[스프링 부트] 2. 어노테이션(Annotation)

lhs's avatar
Nov 14, 2024
[스프링 부트] 2. 어노테이션(Annotation)
💡
어노테이션은 코드 요소에 메타데이터를 추가하여, 코드의 동작을 설명하거나 처리할 정보를 제공하는 특별한 타입의 인터페이스이다.
 

1. 어노테이션이란?

어노테이션(Annotation)은 Java에서 코드에 메타데이터를 추가하는 방법으로, 클래스, 메서드, 필드 등 다양한 코드 요소에 추가적인 정보를 제공한다. 어노테이션은 주로 컴파일러나 런타임 환경에서 처리되며, 코드의 동작에 영향을 미치거나, 문서화 및 검사 등을 위한 목적으로 사용된다. 예를 들어, @Override, @Deprecated와 같은 기본 어노테이션 외에도 개발자가 정의한 어노테이션을 통해 동적 처리를 할 수 있다.

2. 주요 메타어노테이션

  1. @Retention
      • 해당 어노테이션이 어떤 시점까지 유효한지를 지정하는 메타 어노테이션이다. 이 메타 어노테이션은 어노테이션이 소스 코드, 컴파일 타임, 런타임까지 살아있는지 정의한다.
      • 종류
        • RetentionPolicy.SOURCE: 어노테이션이 컴파일러에서만 존재하고, 컴파일된 바이트코드에는 포함되지 않고 주로 코드 분석 도구나 IDE에서만 사용된다.
        • RetentionPolicy.CLASS: 기본값으로, 어노테이션이 클래스 파일에 포함되지만, JVM에서 런타임 동안에는 접근할 수 없다.
        • RetentionPolicy.RUNTIME: 어노테이션이 런타임까지 유지되어, 리플렉션을 통해 런타임에 어노테이션을 읽을 수 있다.
  1. @Target
      • 어노테이션이 어디에 적용될 수 있는지를 지정한다. 예를 들어, 클래스, 메서드, 필드 등에 어노테이션을 적용할 수 있다. 이 메타 어노테이션을 사용하여 어노테이션의 적용 대상을 제한할 수 있다.
      • 종류
        • ElementType.TYPE: 클래스, 인터페이스, 열거형
        • ElementType.FIELD: 필드(변수)
        • ElementType.METHOD: 메서드
        • ElementType.PARAMETER: 매개변수
        • ElementType.CONSTRUCTOR: 생성자
        • ElementType.LOCAL_VARIABLE: 지역 변수
        • ElementType.ANNOTATION_TYPE: 다른 어노테이션
        • ElementType.PACKAGE: 패키지
  1. @Documented
      • 해당 어노테이션이 JavaDocs에 포함되도록 한다. 이 메타 어노테이션을 사용하면, 해당 어노테이션을 적용한 코드가 문서화될 때 JavaDocs에 포함된다.
  1. @Inherited
      • 클래스에만 적용되며, 상속된 클래스에 어노테이션을 자동으로 상속하도록 지정한다. 부모 클래스에 적용된 어노테이션이 자식 클래스에서 자동으로 인식될 수 있도록 한다.
  1. @Repeatable
      • 해당 어노테이션이 여러 번 적용될 수 있도록 허용하는 메타 어노테이션이다. 컨테이너 어노테이션과 함께 사용되며, 컨테이너 어노테이션은 반복된 어노테이션을 배열로 감싸는 역할을 한다.

3. 예제 코드

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequestMapping { String value(); }
RequestMapping.java
 
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("메서드 실행중 오류가 발생했어요."); } } } } }
Router.java
 
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("로그아웃"); } }
UserController.java
 
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); } }
App.java
 

4. 정리

  • RequestMapping 어노테이션 인터페이스
    • @Target(ElementType.METHOD)를 통해 메서드에만 적용될 수 있도록 정의된다.
    • @Retention(RetentionPolicy.RUNTIME)을 통해 어노테이션이 런타임에 읽힐 수 있도록 정의된다.
    • String value() 를 경로를 인자로 받아, 해당 경로와 매칭되는 메서드를 지정한다.
  • Router 클래스
    • UserController 객체를 받아, 경로에 맞는 메서드를 호출하는 역할을 한다.
    • routing() 메서드에서 리플렉션을 사용하여 UserController 클래스의 메서드들을 methods 배열에 넣는다.
    • getAnnotation() 메서드를 통해 RequestMapping 어노테이션을 찾고, 경로(value)와 일치하는 메서드를 실행한다.
  • UserController 클래스
    • 각 메서드에 @RequestMapping 어노테이션을 사용하여 해당 메서드가 처리할 경로를 지정한다.
  • App 클래스
    • scanner를 통해 사용자로부터 경로를 입력받고, 입력된 경로에 맞는 메서드를 실행한다.
Share article

LHS's Study Space