자바의 애노테이션에 대해 학습하세요.
애노테이션 정의하는 방법
@retention
@target
@documented
애노테이션 프로세서
자바 5부터 등장하는 기능으로 주석이라는 의미를 가지고 있다, 하지만 우리가 사용하는 //,/**
와 같은 주석과는 많이 다르다
Annotation
은 설명이라는 의미 뿐만 아니라 그 이상의 활동을 한다.
Annotation
이 붙어있는 코드는 Annotation
의 구현된 정보에 따라 연결되는 방향이 결정된다.
따라서 전체 소스코드에서 비즈니스 로직에 까지 영향을 주지는 않지만 해당되는 타켓의 연결 방법이나 소스코드의 구조를 변경할 수 있다.
쉽게 말해서 이 속성을 어떤 용도로 사용할까, 어떤 역할을 줄까
같은 결정해서 붙여 준다고 보면 된다.
Annotation
은 소드코드에 메타데이터를 삽입하기 때문에 잘 이용하면 직관적인 역할 뿐만 아니라 체계적인 소스코드를 구성하는 데 도움을 준다.
import java.beans.JavaBean;
@JavaBean
public class AnnotationTest {
}
Annotation
은 위 코드와 같이 @(;AT)
을 앞에 붙여서 사용한다.
이 Annotation
은 자바가 기본적으로 제공하기도 하고 (@Deprecated, @Override, @SuppressWarnings),
같이 개발자가 직접 정의해서 사용할 수도 있다.
개발자는 어노테이션을 붙일 타겟과 유지시기 등을 설정하여 자신이 원하는 용도로 활용이 가능하다.
이 어노테이션을 잘 활용하면 비즈니스 로직과는 별도로 시스템 설정과 관련된 부가적인 정보들은 어노테이션에 위임하고 개발자는 비즈니스 로직에 좀 더 집중할 수 있다.
따라서 우리는 어노테티션을 통해 AOP을 편리하게 구성할 수 있다.
어노테이션은 컴파일 시기에 처리될 수 있고, 자바의 리플렉션을 거쳐서 런타임에 처리될 수도 있다.
리플렉션은 실행중인 자바 클래스의 정보를 볼 수 있게 하고, 그 클래스의 구성정보로 기능을 수행할 수 있도록 한다.
종류 | 설명 |
---|---|
@Override | 선언한 메서드가 오버라이드 되었다는 것을 나타냄 (상위(부모)클래스(또는 인터페이스)에서 해당 메서드를 찾지 못하면 컴파일 에러 발생.) |
@Deprecated | 해당 메서드가 더이상 사용되지 않음을 표시합니다. (해당 메서드를 사용할 경우 컴파일 경고를 발생.) |
@SuppressWarnings | 선언한 곳의 컴파일 경고를 무시. |
@SafeVarargs | 제네릭 가은 가변인자 매개변수를 사용할 때의 경고를 무시한다.(Java 7 이상) |
@FunctionalInterface | 람다 함수등을 위한 인터페이스 지정.(Java 8 이상) 메소드가 없거나 두개이상 되면 컴파일 오류 발생 |
종류 | 설명 |
---|---|
@Retention | 어노테이션이 유지되는 기간을 지정하는데 사용한다.(세가지 유지정책 사용) |
@Documented | 해당 어노테이션을 javadoc에 포함시킨다. |
@Target | 어노테이션이 적용할 위치를 지정한다. 여러 값일 경우 {} 사용 |
@Inherited | 어노테이션의 상속을 가능하게 한다. |
@Repeatable | 연속적으로 어노테이션을 사용할 수 있게 해준다. |
import java.beans.JavaBean;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
}
@Target
은 말 그대로 어노테이션의 타겟을 지정하는 것이다.
따라서 해당 어노테이션을 Field 에 붙인다면 FIELD, Class나 Enum 등의 타입에 붙일때는 TYPE 등으로 어떤 대상을 위한 어노테이션인지 설정한다.
그 아래이 있는 @Retention
은 어노테이션의 라이프사이클 즉, 어노테이션이 언제까지 살아 남아 있을지를 정한다.
@Retention
어노테이션의 속성으로 RetentionPolicy
라는 것이 있다.
여기에 올 수 있는 값으로는 source, class, runtime 이렇게 3가지 있다.
@Retention(RetentionPolicy.SOURCE)
소스코드까지만 유지 (즉, 컴파일 과정에서 어노테이션 정보는 사라짐)
롬복에 @Getter
, @Setter
를 살펴보면 @Retention(RetentionPolicy.SOURCE)
로 되어 있다.
하지만 source 정책이기 때문에 .java 소스 파일까지는 어노테이션이 남아있고 컴파일되어 클래스파일이 되면 사라질 것이다.
하지만 롬복 라이브러리는 코드 생성을 하기 때문에 @Getter
가 컴파일될때 사라지는 대신 바이트코드로 생성되어 남아 있다.
굳이 바이트 코드에 어노테이션 정보가 들어갈 필요는 없음
@Retention(RetentionPolicy.RUNTIME)
런타임 시점까지 유지 (Reflection API 로 어노테이션 정보 조회 가능)
런타임에 어노테이션 정보를 뽑아 쓸 수 있다는 의미이다.
스프링을 예로 들자면, @Controller, @Service, @Autowired 등이 있는데 스프링이 올라오는 실행중인 시점에 컴포넌트 스캔이 가능해야하기 때문에 RUNTIME 정책이 필요하다
스프링도 내부적으로 Reflection 등을 활용하여 어노테이션이 붙은 놈들만 가져온다
@Retention(RetentionPolicy.CLASS)
클래스파일 까지만 유지 (런타임시 유지안됨)
인텔리제이에서, @NonNull 등이 붙어있는 경우 null 값을 넣게되면 노랑색 경고로 알려준다.
SOURCE랑 유사한 면이 있지만 Maven/Gradle로 다운받은 라이브러리와 같이 jar 파일에는 소스가 포함되어있지 않고 class 파일만 포함되어있다
class 파일만 존재하는 라이브러리 같은 경우에도 타입체커, IDE 부가기능 등을 사용할수 있으려면 CLASS 정책이 필요하다.
javadoc 으로 api 문서를 만들 때 어노테이션에 대한 설명도 포함하도록 지정해준다.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
requestMapping 에서 value와 path 를 보면 @AliasFor
가 선언되어 있고
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {
@AliasFor("attribute")
String value() default "";
@AliasFor("value")
String attribute() default "";
@AliasFor
를 들어가보면 @Documented
가 선언되어 있다
RequestMapping에 대한 문서화 목록에 value와 path를 보면
@AliasFor(value=”value”) 와 @AliasFor(value=”path”)를 볼 수 있다
즉 @AliasFor에는 @Documented 애노테이션이 메타로 설정되어 있기 때문에 @RequestMapping에서 @AliasFor를 사용하는 필드에 대해서는 @AliasFor가 노출되게 된다.
- Documented : javadoc으로 문서 생성 시 현재 어노테이션 설명 추가
- Retention : 어노테이션을 유지하는 정책 설정
- Target : 어노테이션 적용 위치
Annotation Processor는 컴파일 단계에서 Annotation에 정의된 일렬의 프로세스를 동작하게 하는 것을 의미한다.
컴파일 단계에서 실행되기 때문에, 빌드 단계에서 에러를 출력하게 할 수 있고, 소스코드 및 바이트 코드를 생성할 수도 있다.
사용하는 예로 자바의 @Override
가 있으며, Lombok(롬복) 이라는 라이브러리도 있다.
AnnotationProcessor 가 제공하는 API 는 어노테이션이 붙어 있는 클래스의 정보를 참조하는 기능까지만을 제공한다.
즉, 소스코드의 수정은 API 에서 제공하는 기능은 아니지만 롬복은 컴파일러 내부 클래스를 사용하여 코드를 수정하고 있다.
AnnotationProcessor 개발한 개발자의 의도와 다르게 코드를 사용하는 일종의 해킹 이라고도 볼 수 있지만, 실제로 많은 편의를 제공해주는 라이브러리이기 때문에 많은 개발자들이 사용하고 있다.
https://goodgid.github.io/Spring-MVC-Documented-Annotation/
https://www.nextree.co.kr/p5864/