[Java] 어노테이션(커스텀 어노테이션)

devdo·2023년 9월 3일
0

Java

목록 보기
55/56
post-thumbnail

Java 5(1.5)부터 등장한 기능으로, 한 마디로 요약하면 프로그램에 추가적인 정보를 제공해주는 메타 데이터이다.

여기서 메타 데이터란 어플리케이션이 처리해야 할 데이터가 아니라 컴파일 과정과 런타임에서 코드를 어떻게 컴파일하고 처리할 것인지에 대한 정보를 말한다.

이 메타데이터를 잘 이용하면 비즈니스 로직과 분리하여 대상의 벨리데이션 체크, 값 주입, 역할 부여(기능 주입) 등을 수행할 수 있어 체계가 잡혀있는 깔끔한 코드를 작성할 수 있게 된다.

어노테이션은 옵션에 따라 컴파일 전까지만 유효하도록 처리될 수도 있고, 컴파일 시기에 처리(컴파일러가 클래스를 참조할 때까지)될 수도 있고, 런타임 시기에 처리될 수도 있다.


Java의 리플랙션, AOP와 연관

Java의 리플렉션(실행중인 자바 클래스의 정보를 가져오는 기능)을 사용하여 런타임 시기에 어노테이션의 정보를 바탕으로 다양한 기능을 수행할 수 있으므로 어노테이션은 AOP(관점지향 프로그래밍)을 구성하는 데에 많은 도움을 줄 수 있다.

커스텀 어노테이션의 구성

커스텀 어노테이션은 메타 어노테이션을 사용하여 다음과 같은 구조를 가진다.
메타 어노테이션이란 커스텀 어노테이션을 구성할 때 시점, 위치등을 지정하기 위한 어노테이션이다.
어노테이션의 필드 타입은 enum, String이나 기본 자료형, 기본 자료형의 배열만 사용할 수 있다.

@Target({ElementType.[적용대상]})
@Retention(RetentionPolicy.[정보유지되는 대상])
public @interface [어노테이션명]{
	public 타입 elementName() [default]
    ...
}

메타 어노테이션 정리

1) @Retention
컴파일러가 어노테이션을 다루는 방법을 기술, 어느 시점까지 영향을 미치는지를 결정

RetentionPolicy.SOURCE : 컴파일 전까지만 유효
RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지 유효
RetentionPolicy.RUNTIME : 컴파일 이후 런타임 시기에도 JVM에 의해 참조가 가능(리플렉션)

2) @Target
어노테이션 적용할 위치 선택

ElementType.PACKAGE : 패키지 선언
ElementType.TYPE : 타입 선언
ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
ElementType.CONSTRUCTOR : 생성자 선언
ElementType.FIELD : 멤버 변수 선언
ElementType.LOCAL_VARIABLE : 지역 변수 선언
ElementType.METHOD : 메서드 선언
ElementType.PARAMETER : 전달인자 선언
ElementType.TYPE_PARAMETER : 전달인자 타입 선언
ElementType.TYPE_USE : 타입 선언

3) @Documented
해당 어노테이션을 Javadoc에 포함시킴

4) @Inherited
어노테이션의 상속을 가능하게 함

5) @Repeatable
Java8 부터 지원하며, 연속적으로 어노테이션을 선언할 수 있게 함


어노테이션 동작 원리

어토테이션 타입 선언은 특별한 종류의 인터페이스로 친다. 일반적인 인터페이스와 구분하기 위해
@interface를 붙여 선언한다. 기술적으로 이 둘은 공백으로 분리가 가능하지만 스타일 문제로 분리하지 않는 것을 권장한다고 한다.

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

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
public @interface CustomAnnotation {
  public String value();
}

위의 커스텀 어노테이션을 JDK내장 javap 라는 역어셈블러를 사용해 확인해보면 java.lang.annotation.Annotation 클래스를 상속받음을 알 수 있고, 결과물은 다음과 같아진다.

public interface annotation.CustomAnnotation extends java.lang.annotation.Annotation {
	public abstract java.lang.String value();
}

@interface는 자동으로 Annotation 클래스를 상속(확장)하며, 내부의 메소드들은 abstract 키워드가 자동으로 붙게 된다. 따라서 어노테이션 인터페이스는 extends절을 가질 수 없으며, 추가적으로 다음과 같은 제약이 존재한다.

  • 어노테이션 타입 선언은 제네릭일 수 없다.
  • 메소드는 매개변수를 가질 수 없다.
  • 메소드는 타입 매개변수를 가질 수 없다.
  • 메소드 선언은 throws 절을 가질 수 없다.

(커스텀)어노테이션이 결과적으로 어떻게 이루어지는지는 알겠다. 그렇다면,
어노테이션이 해 주는 역할이 무엇인가? 라는 질문을 할 수 있겠다.

일단 어노테이션 그 자체로는 아무것도 해 주는 일이 없다.
어노테이션은 추가적인 정보를 제공해주는 메타데이터라고 했다.
어노테이션의 역할은 정보를 가짐으로써 끝났다고 볼 수 있다.
이제 이 정보를 이용하는 역할을 하는 다른 누군가가 필요한 것이다.

정보를 이용하려면 일단 어노테이션에 대한 접근이 필요하다.
클래스 메소드와 필드에 관한 어노테이션 정보를 얻고 싶으면, 리플렉션을 이용해서 얻어야 한다.
리플렉션을 이용해 가져온 정보를 토대로 다양한 작업을 수행할 수 있게 되는 것이다.


활용

RestController + Swagger

https://mangkyu.tistory.com/130



참고

profile
배운 것을 기록합니다.

0개의 댓글