-
java Annotation 이해하기Language/Java 2023. 9. 25. 22:17728x90반응형
- 목차
소개.
java Annotation 은 일종의 마커입니다.
Annotation 그 자체만으로 특별한 기능을 수행하는 것은 아닙니다.
Annotation 이 붙은 class, method, field 들이 컴파일러 또는 런타임 환경을 거치면서 특별한 기능을 수행하게 됩니다.
컴파일러가 컴파일을 하던 도중에 특정 Annotation 을 발견한다면,
약속된 Annotation 의 처리방식에 따라서 어노테이션이 붙은 class, method, field 를 컴파일합니다.
그리고 Spring 과 같은 런타임 환경에 어플리케이션을 구동하는 과정에서
Annotation이 붙은 class, method, field 들을 발견하면 이에 상응하는 처리를 수행합니다.
예를 들어보겠습니다.
@Deprecated.
우리가 흔히 하는 @Deprecated Annotation 이 있죠?
@Deprecated Annotation 은 대표적인 Source Retention Annotation 입니다.
이는 컴파일러에 의해서 컴파일되는 과정에서 처리되는 Annotation 입니다.
컴파일러가 java 파일을 bytecode 로 컴파일을 시도하죠.
컴파일하는 과정에서 Deprecated 로 선언된 Method 를 사용하는 함수를 발견하게 된다면,
Deprecated 되었다는 경고문을 출력합니다.
즉, 컴파일러는 컴파일 과정에서 @Deprecated Annotation 이 붙은 함수가
사용되는 코드를 발견하게 되면 경고문을 출력하도록 설정되어 있습니다.
@Override.
@Override Annotation 는 대표적인 Compile-Time Annotation 입니다.
컴파일 과정에서 사용되는 Annotation 이구요.
@Override Annotation 이 적용된 Method 를 자식 클래스에서 Override 하지 않는다면,
해당 컴파일은 실패하게 됩니다.
@Test.
@Test Annotation 은 Runtime Annotation 중의 하나입니다.
Runtime Annotation 은 컴파일러가 아닌 실행 환경에 의해서 처리되는 Annotation 인데요.
JUnit 이라는 Test Framework 에 의해서 처리되는 어노테이션입니다.
java 의 JUnit 테스트 환경에서 첫 단계로 테스트 함수들을 찾는 과정이 있습니다.
이를 Test Discovery 라고 부르는데요.
JUnit Test Engine 이 @Test 라고 어노테이션이 붙은 모든 함수를 스캔하게 됩니다.
( 이 과정에서 Java Reflection 이 사용됩니다. )
즉, JUnit Test Engine 은
모든 classpath 의
모든 class 의
모든 @Test Annotation 가 붙은 method 들을
조회하는 과정을 필수적으로 거칩니다.
이를 Test Method Scan 이라고 합니다.
@Test Annotation 는 하나의 마커로써 사용되는 대표적인 케이스입니다.
@Bean.
스프링을 사용하다보면 수 많은 @Bean Annotation 를 볼 수 있죠.
이 또한 스프링이라는 런타임 환경에 Bean 을 생성하기 위해서 @Bean Annotation 이 붙은 모든 클래스를 찾습니다.
이 또한 @Test 처럼 ComponentScan 과정을 거치죠.
Retention Policy.
Annotation 은 Retention 이라는 중요한 기준이 있습니다.
Retention 이 해당 Annotation 이 유효함을 가지는 시간 정보인데요.
Source, Compile, Runtime 두가지로 나뉩니다.Source.
Retention 이 Source 인 Annotation 은 처리 결과가 Bytecode 에 남지 않습니다.
Annotation 의 수명이 Source Code 인 상태에서만 유지되기 때문에 Source 라고 표현됩니다.
대표적인 Source Retention 은 Deprecated 말고도 Lombok 으로 제공되는 Annotation 들이 있습니다.
@getter, @setter 이 그 예이죠.
Lombok 을 사용하기 위해서는 필수적으로 Lombok annotation processer 가 컴파일 과정에 추가되어야 합니다.dependencies { annotationProcessor 'org.projectlombok:lombok:1.18.22' }
이것은 컴파일 과정의 앞단인 Annotation Processing 단계에서 Lombok Annotation Processor 가 동작함을 뜻합니다.
만약 AnnotationProcessor 가 @getter 또는 @setter 인 field 를 발견한다면,
Lombok Annotation processor 는 해당 field의 set method 와 get method 를 만들어줍니다.
그리고 나서 컴파일이 되는거죠.
Source Retention Annotation 의 특징은
1. 그 수명이 Source Code 를 넘어가지 않습니다.
2. bytecode 에 Source Retention Annotation 의 흔적이 남지 않습니다.
3. Deprecated 같은 built-in annotation 은 컴파일러에 의해서 사전에 정의된 방식으로 처리됩니다.
4. Lombok 과 같은 custom annotation 은 이것들을 처리하기 위한 별도의 Annotation Processor 가 필요합니다. (ex. Lombok Annotation Processor)
Compile.
Compile Retention Annotation 은 컴파일 과정에서 사용되는 Annotation 입니다.
Source Retention Annotation 이 Source Code 레벨에서만 존재하듯이, Compile Retention Annotation 은 bytecode 단계까지만 어노테이션이
유지되고 런타임에선 유지되지 않습니다.
하지만 최근 스펙의 java 에선 Compile Retention Annotation 이 컴파일 과정에서 Runtime Retention 으로 치환되어 런타임 환경에서도 확인할 수 있다고 합니다.
즉, java Reflection 을 통해 Compile Retention Annotation 도 확인이 가능하죠.
<java spec>
대략 Compile Retention Annotation 이 Runtime Retention 으로 변경되어 컴파일된다는 의미입니다.The Java compiler can generate a runtime retention annotation for a compile retention annotation. This is done by generating a compile retention annotation called @Retention(RetentionPolicy.RUNTIME) when it compiles a class that is annotated with a compile retention annotation.
그래서 사실상 기술적으로는 Compile 과 Runtime 의 어노테이션이 큰 차이는 없습니다.
하지만 기존의 컨벤션에 따라 그리고 의미적인 관점에서 따라 다르게 사용되어야 할 뿐이죠.
디저트를 식후에 먹든 식전에 먹든 별 상관은 없지만, 보통 식후에 먹죠?
특히 유럽에선 디저트를 아무때나 먹으면 굉장히 화를 낸다고 합니다.
Compiler 는 Compile Retention Annotation 을 확인하고, 이에 상응하는 처리를 진행할 수 있습니다.
Runtime.
런타임 어노테이션은 굉장히 많은 종류가 있습니다.
왜냐하면 런타임 환경이라는게
Spring, JUnit, Spark, Flink 등등 여러 가지가 존재합니다.
Runtime Retention Annotation 을 사용하기 위해서는 두가지가 필수적으로 필요합니다.1. Custom Runtime Annotation Processor
2. 약속된 Runtime Annotation
Spring, JUnit 처럼 자체적인 Annotation Processor 가 존재해야하구요.
Application 실행 단계에서 Annotation Processing 단계가 실행되어야합니다.
당연히 Annotation Processor 가 처리할 수 있는 약속된 Runtime Annotation 도 필요합니다.
가장 대표적인 Runtime Retention Annotation 은 @Test 와 @Bean 입니다.
관련된 글이 있어서 첨부드립니다.
https://westlife0615.tistory.com/4
https://westlife0615.tistory.com/7
Runtime 에서 Annotation 확인하는 법.
아래 코드는 Field 와 Method 어노테이션을 적용하는 코드입니다.
package org.example; import java.lang.annotation.*; import java.lang.reflect.Field; import java.lang.reflect.Method; public class AnnotationTest { @TestRuntimeAnnotation1() String field1; @TestRuntimeAnnotation2() String getField1 () { return field1; } public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException { Field field1 = AnnotationTest.class.getDeclaredField("field1"); field1.setAccessible(true); Annotation[] fieldAnnotations = field1.getAnnotations(); System.out.printf("field annotation is %s \n", fieldAnnotations[0].annotationType().getName()); Method getField1 = AnnotationTest.class.getDeclaredMethod("getField1"); getField1.setAccessible(true); Annotation[] methodAnnotations = getField1.getAnnotations(); System.out.printf("method annotation is %s \n", methodAnnotations[0].annotationType().getName()); } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface TestRuntimeAnnotation1 { } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface TestRuntimeAnnotation2 { }
<실행 결과>
field annotation is org.example.TestRuntimeAnnotation1 method annotation is org.example.TestRuntimeAnnotation2
이러한 방식으로 모든 Runtime Annotation Processor 들은 classpath 의 모든 클래스들을 스캔하고 Annotation 처리를 수행합니다.
Field, Method, Constructor, Class 들을 조회하게 되죠.
마무리하며.
java 의 Annotation 은 그 자체만으로 특별한 기능을 가지는 것은 아닙니다.
java compiler, Custom Annotation Processor 등을 통해서 비로소 의미를 가지게 됩니다.
Lombok 과 같은 Source Level Annotation 들은 새로운 코드를 생성하거나,
Swagger 같은 기능으로 Documentation 을 생성할 수도 있죠.
그리고 Spring 이나 JUnit 같은 경우도 Runtime Annotation 들을 찾아서
Bean 을 생성하거나 Test 케이스들을 수집할 수 있습니다.
지금까지 java Anontation 의 의미와 쓰임에 대해서 알아보았습니다.
반응형'Language > Java' 카테고리의 다른 글
[Java NIO] NIO 는 어떻게 동작할까 ? (DMA, Kernel Space) (0) 2024.01.31 Jackson 으로 JSON 다루기 (0) 2024.01.22 Java off-heap 메모리 알아보기 (0) 2023.12.22 Java Thread Pool 알아보기 (0) 2023.09.30 Java Future 알아보기 (0) 2023.09.30