1. 어노테이션(annotation)이란
- 공부를 하다보면 @Controller, @Getter와 같은 것을 본 적이 있을텐데 @로 시작되는 요소들을 어노테이션이라고 한다.
- 클래스, 인터페이스를 컴파일할 때 어떻게 처리해야 할 지를 알려주는 정보이다.
2. 어노테이션의 용도
- 컴파일 시 사용하는 정보 전달(예 : @Override)
- 빌드 툴(maven, gradle 등)이 코드를 자동으로 생성할 때 사용하는 정보 전달
- 실행할 때 특정한 기능을 처리할 때 사용하는 정보 전달
3. 어노테이션 사용하기
1) 어노테이션 정의하기
- 인터페이스를 정의하는 것과 비슷하며 속성을 가질 수 있다.
public @interface print{
String value(); // 속성은 타입과 이름으로 되어 있으며, 괄호를 붙인다.
int field1() default 10;
}
2) 어노테이션 사용하기
@HelloWorld(value = "반갑습니다.", field1 = 5)
// field1의 경우 default값을 설정해두었기 때문에 값을 지정하지 않으면 10으로 들어간다.
4. 어노테이션의 적용 대상
- 추가적인 설정 정보인 어노테이션을 사용하기 위해서는 어떤 클래스(혹은 메서드 등)에 적용할 것인지 명시해줘야 한다.
- 적용대상을 지정할 때는 @Target 어노테이션을 사용한다.
ElementType의 상수 |
적용 대상 타입 |
TYPE |
클래스, 인터페이스, Enum |
ANNOTATION_TYPE |
어노테이션 |
FIELD |
필드 |
CONSTRUCTOR |
생성자 |
METHOD |
메서드 |
LOCAL_VARIABLE |
로컬 변수 |
PACKAGE |
패키지 |
- 아래는 클래스, 필드, 메서드 레벨에서만 적용할 수 있고, 생성자에는 적용할 수 없는 어노테이션의 예이다.
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface AnnotationTest{ ... }
@AnnotationTest
public class HelloWorld{
@AnnotationTest
private String field1;
// 생성자는 사용 불가
public HelloWorld(){}
@AnnotationTest
public void method1(){ ... }
}
5. 어노테이션의 유지 정책
RetentionPolicy 상수 |
적용시점 |
제거 시 |
SOURCE |
컴파일 시 적용 |
컴파일 후 제거됨 |
CLASS |
메모리 로딩 시 적용 |
메모리 로딩 후 제거됨 |
RUNTIME |
실행 시 적용 |
계속 유지 |
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest{ ... }
6. 어노테이션의 설정 정보 이용하기
- 앞서 말했듯이 어노테이션은 설정 정보이다.(이 말은 즉, 아무런 기능이 없다는 말이다.)
- 어노테이션의 정보를 다음 메서드를 통해서 알아낼 수 있다.
매서드 |
설명 |
boolean isAnnotationPresent(AnnotationName class) |
지정한 어노테이션이 적용되어 있는가 |
Annotation getAnnotation(AnnotationName.class) |
지정한 어노테이션이 적용되어 있으면 해당 어노테이션 리턴(그렇지 않은 경우 null 리턴) |
Annotation[] getDeclaredAnnotations() |
적용된 모든 어노테이션을 리턴 |
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Print {
String value() default "-";
int number() default 15;
}
public class ServiceTest {
@Print
public void method1() {
System.out.println("method1 실행");
}
@Print("*")
public void method2() {
System.out.println("method2 실행");
}
@Print(value = "#", number = 30)
public void method3() {
System.out.println("method3 실행");
}
}
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class PrintAnnotationTest {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
Method[] declaredMethods = ServiceTest.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
Print annotation = declaredMethod.getAnnotation(Print.class);
printAnnotationInfo(annotation); // 어노테이션 정보를 출력
declaredMethod.invoke(new ServiceTest()); // 메서드 실행 (java Reflection 참고)
printAnnotationInfo(annotation); // 어노테이션 정보를 출력
}
}
public static void printAnnotationInfo(Print printAnnotation) {
if (printAnnotation != null) {
int number = printAnnotation.number();
for (int i = 0; i < number; i++) {
System.out.print(printAnnotation.value());
}
System.out.println();
}
}
}