Programming/JAVA

애너테이션이란?

잇나우 2021. 3. 6. 00:33
반응형

애너테이션이란?

자바를 개발한 개발자들은 소스코드와 그에대한 문서를 하나의 파일로 관리 하는것이 효율적이라고 판단하여 소스코드의 주석에 소스코드에 대한 정보를 저장하고 주석으로부터 HTML 문서를 생성해내는 프로그램인 javadoc.exe을 만들어 사용했다.
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 바로 애너테이션이다.
애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서 다른 프로그램에게 유용한 정보를 제공할 수 있다는 장점이 있다.
JDK에서 제공하는 표준 애너테이션은 주로 컴파일러를 위한 것으로 컴파일러에게 유용한 정보를 제공한다. JDK에서 제공하는 애너테이션은 java.lang.annotation 패키지에 포함되어 있다.

애너테이션은 코드에 넣는 주석이다. 주석과 완전히 같진 않지만 주석과 유사하다. 애너테이션을 기능을 가지고 있는 것이라고 생각할 수 있으나 마크, 표시를 해놓는 주석일 뿐이다.
애너테이션에는 컴파일 시점에 알 수 있는 값만 들어갈 수 있다. 즉 런타임 중에 알아내야 하는 값은 사용할 수 없다.

  • 컴파일 수준에서 해석이 되거나
  • static으로 이미 메모리에 등록이 되어있어야 한다
private static final String hello = "hello";

@PostMapping(hello)
public String hello() {
    return "hello";
}

static final인 정적 변수이기 때문에 @PostMapping의 값으로 사용할 수 있다.

장점

기존의 자바는 선언적 프로그래밍 방식으로 개발을 하면서 각 계층별 설정 데이터들을 XML에 명시했는데 서비스의 규모가 클수록 설정이 많아지고 도메인 처리의 데이터들이 분산되어 있어 수정이 힘들었다. 하지만 애너테이션이 등장하면서 데이터 유효성 검사 등 직접 클래스에 명시해 줄 수 있게 되어 수정이 필요할 때 쉽게 파악할 수 있게 되었고 애너테이션의 재사용도 가능해졌다.

  • AOP를 쉽게 구성할 수 있게 해준다.

용도

용도를 크게 문서화, 컴파일러 체크, 코드 분석과 자동 생성, 런타임 프로세싱으로 나눌 수 있다. 컴파일 타임에 에러를 발생시켜 경고하는 목적으로 사용할 수도 있고 문서화는 컴파일 시 애너테이션이 붙은 데이터를 수집하여 가능하지만 잘 사용하지 않는다.
유효성 검사와 같은 메타데이터로써 사용되고 리플렉션을 이용하여 특정 클래스를 주입할 수도 있다.

메타데이터
어떤 목적을 가지고 만들어진 데이터, 어떤 데이터를 설명해주는 데이터

Reflection
반사, 투영이라는 뜻으로 객체를 통해 클래스의 정보를 분석해내는 기법
ClassName, SuperClass, Constructors, Methods, Fields, Annotations....

빌트인 애너테이션

자바에서 기본적으로 제공해주는 컴파일러를 위한 애너테이션으로 갯수가 많지 않다.

애너테이션 설명
@Override 컴파일러에게 오버라이드한 메서드라는 것을 알린다.
@Deprecated 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
@SuppressWarnings 컴파일러의 특정 경고 메시지를 제거하는 애너테이션으로 개발자의 의도가 있는 코드이지만 컴파일러가 이를 알지 못하고 경고를 띄울때 경고 메시지를 제거할 때 사용한다.
@SafeVarargs 제네릭 같은 가변인자 매개변수 사용시 경고를 무시한다. (JDK 1.7 이상)
@FunctionalInterface 함수형 인터페이스라는 것을 알린다. (JDK 1.8 이상)
@Native native 메서드에서 참조되는 상수 앞에 붙인다. (JDK 1.8)
@Target 애너테이션이 적용가능한 대상을 지정하는데 사용한다.
@Documented 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.
@Inherited 애너테이션이 자손 클래스에 상속되도록 한다.
@Retention 애너테이션이 유지되는 범위를 지정하는데 사용한다.
@Repeatable 애너테이션을 반복해서 사용할 수 있게 한다. (JDK 1.8)

이 중 @Target, @Documented, @Inherited, @Retention, @Repeatable 애너테이션의 경우는 메타 애너테이션이다.

메타 애너테이션

@Retention

애너테이션이 유지되는 기간(Life Time)을 설정하는 애너테이션

  • SOURCE
    소스파일에만 존재하고, 클래스파일에는 존재하지 않는다. 컴파일러에 의해 버려진다.
  • CLASS
    클래스파일에는 존재하지만 런타임 시에 유지할 필요가 없다는 것을 알리고 이 값이 default이다.
  • RUNTIME
    클래스파일에도 존재하고 런타임에 VM에 의해 유지되어 리플렉션을 통해 클래스 파일의 정보를 읽어 처리가 가능하다.

@Target

애너테이션이 적용가능한 대상(동작 대상)을 지정한다.
만약 다른 타입이 온다면 컴파일 에러를 띄운다.
ElementType이라는 enum을 통해 지정한다.

  • TYPE
    Class, Interface(애너테이션 타입 포함), enum, jdk14에서 생긴 record
  • FIELD
    필드 값(프로퍼티), enum 상수값
  • METHOD
    메서드
  • PARAMETER
    메서드 파라미터
  • CONSTRUCTOR
    생성자
  • LOCAL_VARIABLE
    지역 변수
  • ANNOTATION_TYPE
    애너테이션
  • PACKAGE
    자바 패키지

JDK 1.8 이후에 추가

  • TYPE_PARAMETER
    타입 매개변수
  • TYPE_USE
    타입 사용 (JDK 9 이후)
  • MODULE
    모듈

JDK 14 이후에 추가

  • RECORD_COMPONENT
    Record 컴포넌트

@Documented

애너테이션의 정보가 javadoc의 문서에 포함되도록 하는 애너테이션

@Inherited

자식 클래스에게도 애너테이션이 상속되도록 하는 애너테이션

@Repeatable

애너테이션을 반복적을 ㅗ선언할 수 있게 하는 애너테이션

커스텀 애너테이션 정의

@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    String name() default "고길동";
}

@를 붙이는 것을 제외하면 인터페이스 정의하는 방식과 동일하다. 애너테이션 선언부 위에 메타 애너테이션을 붙여 메타 애너테이션을 표시할 수도 있다.
@interface안에 매개변수가 없다면 Maker, 코드와 같이 한개만 존재한다면 Single-value, 두개 이상을 갖고 있다면 Full 애너테이션으로 구분할 수 있고 매개변수의 default 값을 다음과 같이 지정해줄 수도 있다.

public class AnnotationExam {
    @CustomAnnotation
    private String defaultName;

    @CustomAnnotaion(name = "희동이")
    private String customName;

    public AnnotationExam() {
        this.defaultName = "이름없음";
        this.defaultName = "이름없음";
    }

    public String getDefaultName() {
        return defaultName;
    }

    public String getCustomName() {
        return customName;
    }
}

매개 변수 하나는 default로 고길동을 하나는 희동이를 애너테이션 값으로 갖게하고 생성자로 매개변수의 값은 이름없음으로 생성하는 클래스가 있다고 하면 아래와 같이 reflect를 활용하여 애너테이션 값에 접근할 수가 있다.

AnnotationExam annotationExam = new AnnotationExam();
System.out.println("defaultName : " + annotationExam.getDefaultName() +
    "customName : " + annotationExam.getCustomName());

Field[] fields = annotationExam.getClass().getDeclaredFields();
for (Field field : fields) {
    System.out.print(field.getName() + " : ");
    Annotation[] annotations = field.getDeclaredAnnotations();
    for (Annotation annotation : annotations) {
        CustomAnnotation customAnnotation = (CustomAnnotation) annotation;
        System.out.println(customAnnotation.name());
    }
}

> defaultName : 이름없음
> customName : 이름없음
> defaultName : 고길동
> customName : 희동이

매개변수의 값은 이름없음 이지만 각 필드에 할당된 애너테이션의 필드값은 다른것을 볼 수 있다. 만약 애너테이션에 Retention을 RUNTIME으로 하지 않는다면 런타임시에 동작하는 reflection을 이용해서 값을 불러오지 못한다.

애너테이션 프로세서

런타임시에 리플렉션을 사용하는 애너테이션과는 달리 컴파일 타임에 이루어진다.
컴파일 타임에 애너테이션들을 프로세싱하는 javac에 속한 빌드 툴로 애너테이션의 소스코드를 분석하고 처리하기 위해 사용되는 훅이다.
보일러플레이트 코드를 제거하는데 도움이 된다.

참고
https://gowoonsori.site/java/annotation/
https://www.notion.so/37d183f38389426d9700453f00253532

반응형

'Programming > JAVA' 카테고리의 다른 글

Enum이란?  (0) 2021.03.02
멀티 쓰레드 프로그래밍이란?  (0) 2021.03.01
예외란?  (0) 2021.02.13
인터페이스란?  (0) 2021.02.06
패키지란?  (0) 2021.01.21