본문 바로가기
Java

특정 어노테이션이 추가된 자식 클래스를 찾으려고 할 때, 반드시 @Inherit를 사용하자

by 흑시바 2024. 8. 27.

@Inherited는 어노테이션이 클래스에 적용될 때 해당 어노테이션이 하위 클래스에 상속될 수 있도록 한다. 기본적으로 어노테이션은 상속되지 않지만, @Inherited를 사용하면 부모 클래스에 적용된 어노테이션이 자식 클래스에도 적용된다.

 

@Inherited 어노테이션이 없는 경우, (1) 인터페이스를 상속받은 구현체 또는 (2) 자식 클래스에서 해당 어노테이션이 추가되어 있는 클래스를 찾을 수 없게 된다. 이를 확인하기 위해 Spring의 ApplicationContext를 사용하여 어노테이션을 찾는 예제로 확인해 본다.

1. @Inherited 없는 커스텀 어노테이션 정의

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ShibaHolic {
    String value();
}

2. 부모와 자식 클래스를 Bean으로 등록

@ShibaHolic("ParentClass")
@Component
class ParentClass {
}

@Component
class ChildClass extends ParentClass {
}

3. Spring ApplicationContext를 통해 Bean을 찾기

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class.getPackage().getName());
        
        String[] beanNames = context.getBeanNamesForAnnotation(ShibaHolic.class);
        for (String beanName : beanNames) {
            System.out.println("Bean with ShibaHolic: " + beanName);
        }
        
        context.close();
    }
}

 

위 코드에서는 ShibaHolic 어노테이션이 @Inherited로 정의되지 않았기 때문에, ChildClass는 ShibaHolic을 상속받지 않는다. 따라서 ApplicationContext에서 ShibaHolic이 붙은 빈을 찾을 때 ChildClass는 포함되지 않는다.

 

출력 결과는 부모 클래스 하나만 조회되게 된다.

 

Bean with MyAnnotation: parentClass

 

이런 경우, 어노테이션에 @Inherited를 추가하면 자식 어노테이션을 찾을 수 있다.

4. @Inherited 있는 커스텀 어노테이션 정의

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface ShibaHolic {
    String value();
}

 

@Inherited가 있는 경우, 부모 클래스에 선언된 어노테이션이 자식 클래스에 상속되므로 Spring ApplicationContext에서 어노테이션을 찾을 때 자식 클래스도 포함된다.

 

다시 main()을 실행하면 다음과 같은 결과를 얻을 수 있다.

 

Bean with MyAnnotation: parentClass
Bean with MyAnnotation: childClass

@Inherited의 작동 원리 = 리플렉션

@Inherited 어노테이션은 Java 리플렉션 API와 함께 동작한다. Java 리플렉션 API는 런타임에 클래스, 메서드, 필드 등의 메타데이터를 검사하고 조작할 수 있는 기능을 제공한다. @Inherited는 이러한 리플렉션 API를 통해 부모 클래스의 어노테이션을 자식 클래스에 상속하는 역할을 한다.

 

리플렉션 API는 클래스의 메타데이터를 검사할 때 @Inherited 어노테이션이 적용된 경우, 부모 클래스의 어노테이션을 자식 클래스에서도 찾을 수 있도록 한다.

 

이와 같이 @Inherited는 리플렉션 API와 함께 동작하여 부모 클래스의 어노테이션을 자식 클래스에서도 사용할 수 있도록 한다. 이를 통해 코드의 재사용성과 일관성을 높일 수 있다.

 

Bean을 생성하고 어노테이션을 통해 자식 클래스까지 해당 어노테이션이 있는 경우 찾고자 하는 경우에는 @Inherited를 사용해야 하는 것을 잊지 말자.

댓글