[Java] 어노테이션 정리
어노테이션이란?
어노테이션은 메타 데이터로서, 프로그램 그 자체의 일부분은 아니지만 프로그램에 대한 데이터를 제공한다. 그래서 어노테이션 자체는 어노테이션을 붙은 코드 동작에 영향을 미치지는 않는다. 참고로 어노테이션은 다음과 같은 상황에 사용된다.
- 컴파일러에게 필요한 정보를 제공
- 컴파일러가 에러를 감지하거나, 경고를 띄우지 않게 하기 위함.
- 컴파일/배포 시에 필요한 처리 기능
- SW 개발 툴에서 어노테이션의 정보를 통해 특정 코드를 추가할 수 있음.
- 런타임 처리 제공
- 런타임에도 어노테이션의 정보를 통해 필요한 처리를 할 수 있음. (Java Reflection)
요약하자면, 어노테이션은 다음과 같이 정의가 가능하다.
어노테이션은 작성한 코드에 대해 추가적인 정보를 제공하면서 컴파일 타임 혹은 런타임 시점에서 해당 코드에 필요한 추가적인 처리를 해 주는 역할을 한다.
메타 어노테이션
메타 어노테이션은 어노테이션을 위한 어노테이션
으로, 어노테이션을 정의할 때 사용된다.
@Target
어노테이션이 적용 가능한 대상을 지정한다.
- ElementType.TYPE
- 클래스, 인터페이스, 열거 타입
- ElementType.ANNOTATION_TYPE
- 어노테이션
- ElementType.FIELD
- 필드
- ElementType.CONSTRUCTOR
- 생성자
- ElementType.METHOD
- 메소드
@Retention
어노테이션이 유지되는 기간을 지정한다.
- RetentionPolicy.SOURCE: 소스 코드(.java)까지 남아있는다.
- 컴파일 전까지만 유효하다.
- RetentionPolicy.CLASS: 클래스 파일(.class)까지 남아있는다. (=바이트 코드)
- 클래스 로더가 클래스를 로딩하기 전까지만 유효하다.
- RetentionPolicy.RUNTIME: 런타임까지 남아 있는다. (사실상 사라지지 않는다.)
- 클래스를 로딩한 이후에도 유효하다.
- Java 리플렉션 API를 사용하여 어노테이션 정보를 알 수 있다.
@Documented
해당 어노테이션을 javadoc에 포함시킨다.
@Inherited
어노테이션의 상속을 가능하게 한다.
@Repeatable
어노테이션을 반복해서 적용할 수 있게 한다.
표준 어노테이션
표준 어노테이션은 자바에서 기본적으로 제공하는 어노테이션을 의미한다.
@Override
컴파일러에게 오버라딩하는 메소드라는 것을 알린다.
@Deprecated
앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
@SuppressWarnings
컴파일러의 특정 경고 메시지가 나타나지 않게 해 준다.
@SafeVarargs
제네릭 타입의 가변 인자에 사용한다.
@FunctionalInterface
함수형 인터페이스라는 것을 알린다.
@Native
native 메소드에서 참조되는 상수 앞에 붙인다.
그 외, 모든 메타 어노테이션은 표준 어노테이션에 속한다.
어노테이션이 사용되는 상황
@Override
클래스를 상속하거나, 인터페이스를 구현하는 과정에서 @Override 어노테이션을 사용하는데, 해당 어노테이션은 다음과 같이 정의되어 있다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
해당 어노테이션은 Method가 target이고, 소스 코드 범위까지 유효하다.
@Service
스프링 프레임워크에서 자주 쓰이는 @Service 어노테이션은 핵심 비즈니스 로직을 담은 서비스 클래스를 빈으로 등록하기 위해 사용된다. @Service 어노테이션은 다음과 같이 정의되어 있다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
해당 어노테이션은 Type이 target이고, 런타임 시점까지 유효하다. 참고로, @Component는 스프링에서 관리되는 빈을 뜻한다.
@GetMapping
스프링 프레임워크에서 자주 쓰이는 @GetMapping 어노테이션은 @GetMapping 안에 적어둔 URL로 GET 요청이 들어오면, 해당 어노테이션이 붙은 메소드가 실행된다. @GetMapping 어노테이션은 다음과 같이 정의되어 있다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
@AliasFor(annotation = RequestMapping.class)
String name() default "";
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
해당 어노테이션은 Method가 Target이고, 런타임 시점까지 어노테이션이 유효하다. 앞선 어노테이션들과는 달리 어노테이션 내부에 다양한 필드들이 정의되어 있다. 이곳에서 필드를 적절히 사용하여 다음과 같이 정의해 줄 수 있다. 참고로 @RequestMapping 어노테이션의 method 속성은 특정 메소드의 요청만 오도록 필터링을 한다.
@GetMapping(value = "/stations", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<StationResponse>> showStations() {
return ResponseEntity.ok().body(stationService.findAllStationResponses());
}
value가 위에서 언급한 URL에 해당한다.
커스텀 어노테이션을 정의하는 방법
기존에 있는 어노테이션을 혼합하여 재활용하는 방법도 있겠지만, 이번 포스팅에서는 순수하게 어노테이션을 정의해보겠다. 간단한 예제를 위해 @Target, @Retention 정도만 사용하여 위의 @GetMapping을 흉내내려고 한다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JayonAnnotation {
String value();
String[] produces();
}
어노테이션 타입 선언은 @interface를 사용해야 하고, 그 옆에 어노테이션의 이름을 적으면 된다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JayonAnnotation {
String value();
String[] produces();
}
public class TestController {
@JayonAnnotation(value = "/jayon", produces = "json")
public void speak() {
System.out.println("My name is Jayon");
}
}
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
final TestController testController = new TestController();
final Method testMethod = testController.getClass().getMethod("speak");
final JayonAnnotation annotation = testMethod.getAnnotation(JayonAnnotation.class);
final String value = annotation.value();
final String[] produces = annotation.produces();
System.out.println("value = " + value);
System.out.println("produces = " + produces[0]);
}
}
// 실행 결과
value = /jayon
produces = json
@JayonAnnotation은 런타임 시점까지 유효하므로 리플렉션을 사용하여 접근할 수 있다. 그래서 해당 어노테이션의 필드 값(value, produces)을 가져올 수 있다.
어노테이션을 통해 정의해 둔 값을 추출하여 런타임에 필요한 세팅을 해줄 수 있고, 이러한 원리로 스프링에서는 @GetMapping을 통해 매핑될 URL을 지정해 줄 수가 있다.
출처
- https://joel-dev.site/83?category=1018629
- https://parkadd.tistory.com/54
- https://jeong-pro.tistory.com/234
예상 면접 질문 및 답변
어노테이션이란?
어노테이션은 작성한 코드에 대해 추가적인 정보를 제공하면서 컴파일 타임 혹은 런타임 시점에서 해당 코드에 필요한 추가적인 처리를 해 주는 역할을 한다.
메타 어노테이션의 종류는?
@Target
어노테이션이 적용 가능한 대상을 지정한다.
- ElementType.TYPE
- 클래스, 인터페이스, 열거 타입
- ElementType.ANNOTATION_TYPE
- 어노테이션
- ElementType.FIELD
- 필드
- ElementType.CONSTRUCTOR
- 생성자
- ElementType.METHOD
- 메소드
@Retention
어노테이션이 유지되는 기간을 지정한다.
- RetentionPolicy.SOURCE: 소스 코드(.java)까지 남아있는다.
- 컴파일 전까지만 유효하다.
- RetentionPolicy.CLASS: 클래스 파일(.class)까지 남아있는다. (=바이트 코드)
- 클래스 로더가 클래스를 로딩하기 전까지만 유효하다.
- RetentionPolicy.RUNTIME: 런타임까지 남아 있는다. (사실상 사라지지 않는다.)
- 클래스를 로딩한 이후에도 유효하다.
- Java 리플렉션 API를 사용하여 어노테이션 정보를 알 수 있다.
@Documented
해당 어노테이션을 javadoc에 포함시킨다.
@Inherited
어노테이션의 상속을 가능하게 한다.
@Repeatable
어노테이션을 반복해서 적용할 수 있게 한다.
표준 어노테이션의 종류는?
@Override
컴파일러에게 오버라딩하는 메소드라는 것을 알린다.
@Deprecated
앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
@SuppressWarnings
컴파일러의 특정 경고 메시지가 나타나지 않게 해 준다.
@SafeVarargs
제네릭 타입의 가변 인자에 사용한다.
@FunctionalInterface
함수형 인터페이스라는 것을 알린다.
@Native
native 메소드에서 참조되는 상수 앞에 붙인다.
그 외, 모든 메타 어노테이션은 표준 어노테이션에 속한다.
'프로그래밍 언어 > Java' 카테고리의 다른 글
Java Collections Framework(JCF)란? - Map (JAVA) (2) | 2021.02.14 |
---|---|
Java Collections Framework(JCF)란? - Set (JAVA) (0) | 2021.02.13 |
Java Collections Framework(JCF)란? - Queue와 Deque (JAVA) (0) | 2021.02.12 |
Java Collections Framework(JCF)란? - JCF의 계층 구조와 List (JAVA) (0) | 2021.02.11 |
Java Collections Framework(JCF)란? - JCF의 정의와 특징 (JAVA) (0) | 2021.02.10 |
댓글