학습목표
어노테이션
을 사용하는 이유 (효과) 는 무엇일까?- 나만의
어노테이션
은 어떻게 만들 수 있을까?
어노테이션
은메타데이터
의 한 형태이다.
메타 데이터는 또 뭐고, 어노테이션은 무슨 뜻이지?
메타 데이터
어노테이션
어노테이션은 다음 세 가지 용도로 사용이 된다.
1) 컴파일러에게 코드 문법 에러를 체크 관련 정보를 제공. ex) @Override
2) 소프트웨어 개발 톨이나 빌드시 코드를 자동으로 생성 할 수 있도록 정보를 제공함. ex) @QueryEntity
2) 런타임 시(실행시) 특정 기능을 실행하도록 정보를 제공 ex) @Scheduled
, @Async
@Override
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
public void sond() { // "The method sond() of type Cat must override or implement a supertype method"
System.out.println("Dog barks");
}
}
위의 코드에서는 오버라이딩한 메서드인 sound
의 철자가 틀려서 컴파일러가 경고 메시지를 출력한다.
@Scheduled
이 어노테이션을 메서드 위에 붙이면 해당 메서드가 주기적으로 실행되도록 스케줄링을 통해 동작한다.
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyScheduledTask {
@Scheduled(fixedRate = 5000) // 5초마다 실행
public void myTask() {
// 특정 기능 실행
System.out.println("mytask executed");
}
}
위 코드를 실행을 하면 5초 마다 mytask executed
라는 메시지를 콘솔창에 출력한다.
사용자 정의 주석의 기본 구조는 다음과 같다.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) // Can be changed to TYPE, FIELD, etc., based on where you want to use it
public @interface YourCustomAnnotation {
// Define annotation elements here
String value() default "Default Value";
}
RetentionPolicy.RUNTIME
은 런타임 시점에서도 어노테이션이 유지가 된다.@Target(ElementType.METHOD)
는 메서드에 사용자 정의 어노테이션을 사용한다는 뜻이됨.String value() default "Default Value";
는 어노테이션의 멤버 변수로 default
뒤에 기본값은 "Default Value"이다. 런타임 시에 클래스에 대한 메타 정보를 얻는 기능을 의미함
자바의 리플렉션에서는 런타임 동안에 객체의 클래스 이름, 메서드, 타입 등의 정보를 추출할 수 있다.
getMethods()
를 통해 해당 클래스의 대한 정보를 가져오고 invoke
를 이용해서 해당 메서드를 실행 할 수 도 있음.
주로 테스트나 재컴파일 없이 동적으로 클래스 속성을 바꾸는 용도로 쓰인다.
해당 객체에 대한 메타 정보들(해당 객체의 클래스명, 메서드, 등)을 가져오는 방식으로 테스할 때 쓸 수 있다.
public class TestRunner {
public void runTest(String className, String methodName) throws Exception {
Class<?> clazz = Class.forName(className);
Object instance = clazz.newInstance();
Method method = clazz.getDeclaredMethod(methodName);
method.setAccessible(true);
method.invoke(instance);
}
}
// Usage
new TestRunner().runTest("com.example.MyTestClass", "testMethod");
package com.practice.annotation.vogella;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface CanRun {
String author() default "konakyeon";
int number() default 5;
}
@Target
은 메서드에만 적용되도록하고, @Retention
은 런타임 시까지 어노테이션 정보를 유지하게 함.package com.practice.annotation.vogella;
public class AnnotationRunner {
@CanRun
public void method1(){
System.out.println("method1");
}
public void method2() {
System.out.println("method2");
}
@CanRun(author = "Minho", number = 10)
public void method3(){
System.out.println("method3");
}
@CanRun(author = "Zeeto", number = 11)
public void method5(){
System.out.println("method4");
}
}
package com.practice.annotation.vogella;
import java.lang.reflect.Method;
public class MyTest {
public static void main(String[] args) {
AnnotationRunner runner = new AnnotationRunner();
Method [] methods = runner.getClass().getMethods();
for (Method method : methods) {
CanRun annos = method.getAnnotation(CanRun.class);
if(annos != null) {
try {
method.invoke(runner);
System.out.println("author:" + annos.author());
System.out.println("number" + annos.number()+"\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
Method [] methods = runner.getClass().getMethods();
:getClass().getMethods()
통해서 runner
객체에 어노테이션이 적용된 메소드들의 정보를 가져와서 methods
변수에 저장함.
CanRun annos = method.getAnnotation(CanRun.class);
annos
객체에 author
와 number
를 가져와서 저장한다.
method.invoke(runner);
runner
의 메서드들을 호출시킴. 위 코드를 실행 시켜 보면 method1
, method2
, method3
를 실행 시킨다.
System.out.println("author:" + annos.author()); System.out.println("number" + annos.number()+"\n");
어노테이션 정보를 출력함. 각 메서드에 넣은 author
와 number
변수 를 출력함.
method2는 어노테이션을 하지 않았기 때문에 출력되지 않았다.
☕ 자바 제네릭(Generics) 개념 & 문법 정복하기