질문
1. 어노테이션을 사용하는 이유 (효과)는 무엇일까?
2. 나만의 어노테이션은 어떻게 만들 수 있을까?
1. 어노테이션을 사용하는 이유 (효과) 는 무엇일까?
Annotation 이란?
어노테이션은 메타 데이터로서, 프로그램 그 자체의 일부분은 아니지만 프로그램에 대한 데이터를 제공한다. 그래서 어노테이션 자체는 어노테이션을 붙은 코드 동작에 영향을 미치지는 않는다.
대부분이 많이 봤을 만한 @Override, @Deprecated 가 Annotation 예로 Annotation의 구현된 정보에 따라 연결되는 방향이 결정됩니다.
참고로 어노테이션은 다음과 같은 상황에 사용된다.
- 컴파일러에게 필요한 정보를 제공
- 컴파일러가 에러를 감지하거나, 경고를 띄우지 않게 하기 위함.
- 컴파일/배포 시에 필요한 처리 기능
- SW 개발 툴에서 어노테이션의 정보를 통해 특정 코드를 추가할 수 있음.
- 런타임 처리 제공
- 런타임에도 어노테이션의 정보를 통해 필요한 처리를 할 수 있음. (Java Reflection)
요약하자면, 어노테이션은 다음과 같이 정의가 가능하다.
어노테이션은 작성한 코드에 대해 추가적인 정보를 제공하면서 컴파일 타임 혹은 런타임 시점에서 해당 코드에 필요한 추가적인 처리를 해 주는 역할을 한다.
메타데이터란?
애리케이션이 처리해야 할 데이터가 아닌 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지 알려주는 정보.
데이터를 위한 데이터. 데이터를 설명해주는 데이터
2. 나만의 어노테이션은 어떻게 만들 수 있을까?
Meta Annotation
Annotation을 직접 커스터마이징을 할 수 있는데 이를 가능하게 하기 위해서는 Meta Annotation을 알아야 합니다.
@Target
Annotaion의 적용 범위는 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 : 타입 선언
@Retention
어노테이션이 유지되는 기간을 지정한다.
RetentionPolicy.RUNTIME : 컴파일 이후에도 JVM읠 통해 계속 참조가 가능. 대표적으로는 리플렉션이나 로깅에 사용
RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지만 유효
RetentionPolicy.SOURCE : 컴파일 전까지만 유효. 컴파일 이후에는 사라지게 된다.
@Documented
문서에 어노테이션 정보가 표기한다.
@Inherited
자식 클래스가 어노테이션을 상속받도록 한다.
@Repeatable
어노테이션을 반복해서 적용할 수 있게 한다.
표준 Annotation
표준 어노테이션은 자바에서 기본적으로 제공하는 어노테이션을 의미한다.
@Override
컴파일러에게 오버라딩하는 메서드라는 것을 알린다.
@Deprecated
앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
@SuppressWarnings
컴파일러의 특정 경고 메시지가 나타나지 않게 해 준다.
@SafeVarargs
제네릭 타입의 가변 인자에 사용한다.
@FunctionalInterface
함수형 인터페이스라는 것을 알린다.
@Native
native 메소드에서 참조되는 상수 앞에 붙인다.
그 외, 모든 메타 어노테이션은 표준 어노테이션에 속한다.
Annotation 생성
1일차에서 배운 @GetMapping 어노테이션과 비슷하게 나만의 어노테이션을 만들어보려고 한다.
@GetMapping 어노테이션은 다음과 같이 정의되어 있다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class)
String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
* @since 4.3.5
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
위에서 정리했던 메타어노테이션들이 보일 텐데
Method가 Target이고, 런타임 시점까지 어노테이션이 유효하며,
어노테이션을 선언 시 사용한 클래스가 문서화될 경우 해당 어노테이션이 적용되었음을 명시하도록 한다.
나는 Target과 Retention 만 사용해서 나만의 어노테이션을 만들어보겠다.
1. @interface를 통해 어노테이션 클래스를 작성할 수 있다.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 어노테이션 적용 대상 Type으로 설정
@Retention(RetentionPolicy.RUNTIME) // 런타임 시까지 어노테이션을 사용
public @interface Custom {
String name();
int number() default 1; //기본값을 1로 지정할수있다
}
새로 만든 커스텀 어노테이션은 @[어노테이션 이름]으로 메서드 앞에 붙여서 사용할 수 있다.
public class TestController {
@Custom(name = "2no", number = 22)
public void custom() {
System.out.println("Hello");
}
}
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
final TestController testController = new TestController();
final Method testMethod = testController.getClass().getMethod("custom");
final Custom annotation = testMethod.getAnnotation(Custom.class);
final String name = annotation.name();
final int number = annotation.number();
System.out.println("name = " + name + "number = " + number);
}
}
@cusTom 은 런타임 시점까지 유효하므로 리플렉션을 사용하여 접근할 수 있다. 그래서 해당 어노테이션의 필드 값(name, number)을 가져올 수 있다.
런타임에는 리플렉션 API를 사용하여 어노테이션 정보에 접근할 수 있다. 이를 통해 개발자는 실행 중인 프로그램에서 클래스, 메서드, 필드 등에 적용된 어노테이션을 검사하고, 해당 어노테이션에 지정된 정보를 가져 올 수가 있다.
어노테이션을 통해 정의해 둔 값을 추출하여 런타임에 필요한 세팅을 해줄 수 있고, 이러한 원리로 스프링에서는 @GetMapping을 통해 매핑될 URL을 지정해 줄 수가 있다.
'인프런 워밍업 스터디 > 과제' 카테고리의 다른 글
[인프런 워밍업 스터디 클럽 0기 - BE] #6 과제 (0) | 2024.02.26 |
---|---|
[인프런 워밍업 스터디 클럽 0기 - BE] #5 과제 (0) | 2024.02.23 |
[인프런 워밍업 스터디 클럽 0기 - BE] #4 과제 (0) | 2024.02.22 |
[인프런 워밍업 스터디 클럽 0기 - BE] #3 과제 (0) | 2024.02.21 |
[인프런 워밍업 스터디 클럽 0기 - BE] #2 과제 (0) | 2024.02.20 |