Java

Java annotation(2) - Custom Annotation

구티맨 2022. 4. 1. 16:20

목차

    사용자 정의 어노테이션을 정의하여, 특정 메소드에 정의한 어노테이션을 선언하고

    이 어노테이션이 정의 되어 있는 메소드를 찾아 메소드 이름을 출력하는 스프링부트 프로그램을 작성해보겠습니다.

    Annotation 정의

    @interface를 사용하여 Print 어노테이션을 정의합니다.

    어노테이션에 3개의 element를 정의합니다.

    메소드에 적용 및 런타임에 사용하기 위해 Retention과 Target을 선언합니다.

    package com.example.anno.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = ElementType.METHOD)
    public @interface Print {
        String value() default "";
    
        String name();
        String[] alias();
    }

    Annotation 사용

    bark 메소드에 Print 어노테이션을 선언하며, element의 값을 설정합니다.

    @Component
    public class Dog {
        @Print(value = "test", name = "doggy", alias = {"bom","bum"})
        public void bark(){
            System.out.println("Dog barked ---");
        }
    }

    Annotation 처리 코드 작성

    Dog 클래스의 선언된 메소드 중에 Print 어노테이션의 선언되어있는 함수가 있으면 메소드의 이름을 출력해주고,

    어노테이션의 Element 값을 출력해줍니다.

    @Component
    public class MyApplicationRunner implements ApplicationRunner {
        Dog dog;
    
        public MyApplicationRunner(Dog dog) {
            this.dog = dog;
        }
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            for(Method method : dog.getClass().getDeclaredMethods()){
                if(method.isAnnotationPresent(Print.class)){
                    System.out.println("annotated method : " + method.getName());
                    Print annotation = method.getAnnotation(Print.class);
                    System.out.println("value : " + annotation.value() + ", name : " + annotation.name() + ", alias : " + Arrays.toString(annotation.alias()));
                }
            }
        }
    }

    어노테이션 정의시에 사용되었던 Retention과 Target에 대해 자세히 알아보도록 하겠습니다.

    Retention

    어노테이션이 언제까지 유효한지를 명시합니다.

    • SOURCE : 컴파일러에 의해 사라지는 어노테이션으로 CLASS파일에 저장되지 않고 source상에서만 확인이 가능하여 주석 같은 용도로 사용합니다.
    • CLASS( Default ) : 컴파일러에 의해 CLASS 파일에 저장은 되지만, 런타임에는 유효하지 않습니다.
    • RUNTIME : 런타임에도 유효합니다.

    Target

    어노테이션을 JAVA의 어떤 엘레멘트에 적용할지 명시합니다.

    총 11가지의 엘레먼트 타입이 있으며, 아래 몇 가지만 소개를 하겠습니다.

    • TYPE : 모든 타입에 사용 가능( ex. class, interface, enum, annotation )
    • METHOD : 메서드에 사용 가능
    • FIELD : 필드에 사용 가능
    • CONSTRUCTOR : 생성자에 적용
    • ANNOTATION_TYPE : 다른 어노테이션에 적용하기 위해 사용되는 타입.( ex @Target, @Retetion )

     

    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
    
    	/**
    	 * Declares whether the annotated dependency is required.
    	 * <p>Defaults to {@code true}.
    	 */
    	boolean required() default true;
    
    }

    마지막으로 Spring Boot에서 많이 사용하는 Autowired라는 어노테이션을 보면,

    런타임에 유효하고, 생성자, 메소드, 파라미터, 필드 그리고 다른 어노테이션에 적용을 할 수 있으며 required라는 엘레멘트를 가진다는 것을 알 수 있습니다.