본문 바로가기
Java

[자바 라이브 스터디] 12. 어노테이션

by 매트(Mat) 2021. 10. 19.

12주차 과제: 애노테이션

목표

자바의 애노테이션에 대해 학습하세요.

 

학습할 것

  • 어노테이션 정의하는 방법
  • @retention
  • @target
  • @documented
  • 애노테이션 프로세서




어노테이션 정의하는 방법

어노테이션(Annotation)은 스프링에서 많이 쓰이죠. 특히 스프링 부트로 넘어가면 정말 모든게 어노테이션으로 되어 있어서 편하게 비즈니스 로직에 집중할 수 있게 되었습니다. 우리에게 편리함을 제공한다는 것은 알겠는데 도대체 어노테이션이란 무엇인가.

 

어노테이션은 사전적 의미로는 주석이라는 뜻입니다. 자바에서 어노테이션은 코드 사이에 주석처럼 쓰여서 특별한 의미, 기능을 수행하도록 하는 기술입니다. 즉, 프로그램에 추가적인 정보를 제공해주는 메타데이터라고 볼 수 있습니다.

 

어노테이션의 용도는 다음과 같습니다.

  • 컴파일타임에 코드 작성 문법 에러를 체크하도록 정보를 제공합니다. 예를 들어 @Override 어노테이션 같은 경우 오버라이딩된 메소드라는 것을 명시해주는 어노테이션입니다. @Override는 오버라이딩된 메소드 위에다가 사용하는데 굳이 사용안해줘도 됩니다. 하지만 사용하는 이유는 협업할 때 이 메소드가 오버라이딩된 메소드인지 구별하기가 힘듭니다. 그래서 사용하고 또 다른 이유는 컴파일타임에 문법 에러를 체크합니다. 만약 오버라이딩된 메소드가 아닌 메소드에 @Override 어노테이션을 사용할 경우 컴파일 에러를 발생시킵니다.
  • 런타임시에 특정 기능을 실행하도록 정보를 제공합니다.
  • 코드를 자동 생성할 수 있도록 정보를 제공합니다. 이 경우는 롬복을 생각할 수 있겠네요.

 

어노테이션 정의

package azurealstn;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "-";
    int number() default 15;
}

어노테이션을 적용하기 위해서는 어노테이션이 어디에 적용되며 언제까지 어노테이션 소스가 유지될 것인지를 설정해야 합니다.




@Target

@Target에는 어떠한 값(클래스나 필드, 메소드 등등...)에 어노테이션을 적용할 것인지를 결정합니다.

어떠한 값:

  • TYPE : 클래스, 인터페이스, Enum
  • ANNOTATION_TYPE : 어노테이션
  • FIELD : 필드
  • CONSTRUCTOR : 생성자
  • METHOD : 메소드
  • LOCAL_VARIABLE : 로컬 변수
  • PACKAGE : 패키지




@Retention

@Retention에는 @Target에서 정한 어떠한 값을 언제까지 유지할 것인지를 결정합니다. 보통은 런타임 시에 많이 사용하여 RetentionPolicy.RUNTIME을 사용합니다.

언제까지 유지:

  • SOURCE : 소스상에서만 어노테이션 정보를 유지. 소스 코드를 분석할 때만 의미가 있으며, 바이트코드 파일에는 정보가 남지 않습니다.
  • CLASS : 바이트코드 파일까지 어노테이션 정보를 유지합니다.
  • RUNTIME : 런타임까지 어노테이션 정보를 유지합니다.

 

위에서 정의한 어노테이션을 실행시켜보겠습니다.

UseAnnotation Class

package azurealstn;

public class UseAnnotation {

    @MyAnnotation
    public void print() {
        System.out.println("UseAnnotation.print");
    }

    @MyAnnotation("*")
    public void print2() {
        System.out.println("UseAnnotation.print2");
    }

    @MyAnnotation(value = "*", number = 20)
    public void print3() {
        System.out.println("UseAnnotation.print3");
    }
}

Main Class

package azurealstn;

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        Method[] methods = UseAnnotation.class.getMethods();

        for (Method m : methods) {
            if (m.isAnnotationPresent(MyAnnotation.class)) {
                System.out.println(m.getName()); //메소드 네임 출력
                MyAnnotation myAnnotation = m.getDeclaredAnnotation(MyAnnotation.class);

                String value = myAnnotation.value();
                int number = myAnnotation.number();
                System.out.println("value = " + value); //value값 출력
                System.out.println("number = " + number); //number값 출력
            }
        }
    }
}

저는 리플렉션을 잘 모릅니다. 하지만 위의 코드는 리플렉션을 몰라도 이해할 수 있습니다.
메소드를 가져와서 배열에 담고 배열을 순회하면서 각 정보를 출력해내는 코드입니다.




@Documented

@Documented은 메타데이터 어노테이션입니다. 이 어노테이션을 사용하는 클래스가** javadoc과 같은 문서화될 때 해당 어노테이션이 적용되었음을 명시**하도록 합니다.

package azurealstn;

import java.lang.annotation.*;

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "-";
    int number() default 15;
}




어노테이션 프로세서

어노테이션 프로세서는 컴파일 시점에 끼어들어 특정한 어노테이션이 붙어있는 소스코드를 참조해서 새로운 소스코드를 만들어 낼 수 있는 기능입니다.

 

어노테이션 프로세서를 사용하는 예로 롬복(Lombok)이 있고, @Override 등등이 있습니다.

어노테이션 프로세싱 과정

  1. 어노테이션 클래스 생성
  2. 어노테이션 파서 클래스 생성
  3. 어노테이션 사용
  4. 컴파일하면 어노테이션 파서가 어노테이션을 처리
  5. 자동 생성된 클래스가 빌드 폴더에 추가

Annotation Parser classes는 오직 프로젝트를 컴파일할 때만 필요합니다. 빌드가 끝나면 쓰이지 않습니다.




References

댓글