2017-12-14 9 views
1

abstract 클래스가 여러 개의 구체적인 클래스로 확장되었습니다. 추상 클래스 초기화 블록은 특정 주석이 달린 메소드를 검색하는 현재 클래스 계층의 모든 메소드를 가져옵니다. 리플렉션 - 여러 서브 클래스에 대한 메서드 캐싱


{ 
    ... 

    final List<Method> methods = new ArrayList<>(16); 
    Clazz<?> clazz = getClass(); 

    while (clazz != Object.class) { 
     for (final Method method : clazz.getDeclaredMethods()) { 
     if (method.isAnnotationPresent(MyAnnotation.class)) { 
      methods.add(method); 
     } 
     } 

     clazz = clazz.getSuperclass(); 
    } 

    METHODS.put(getClass(), methods); 

    ... 
} 

이 구체적인 클래스

ConcreteClass2 > ConcreteClass1 > AbstractClass 
OtherConcrete1 > AbstractClass 

는 웹/응용 프로그램 서버에서 인스턴스화하고 Servlet의 내부에 사용된다. 자체 Reflection으로

가장 빠른 아니다, 나는 검사에게 구체적인 형식이 인스턴스화 될 때마다 (new)를 반복하지 않는 한, 주석 Method 년대를 캐시 할 수있는 최선의 전략은 무엇인가.

실제로 을 <Class<? extends AbstractClass>, List<Method>>으로 사용하고 있습니다. 초기화 블록에서 Map에 이미 최상위 콘크리트 유형 항목이 있는지 확인합니다.

그러나 나는 이것을 처리하는 가장 좋은 방법이라고 생각하지 않습니다. 그런데 외부 의존성을 가질 수는 없습니다. 이 클래스 당 방법을 캐시, 같은 클래스 List<Method>을 재 계산 피할 것이다

private static final ConcurrentMap<Class<?>,List<Method>> METHODS = new ConcurrentHashMap<>(); 
... 
Clazz<?> clazz = getClass(); 
METHODS.computeIfAbsent(clazz, c -> findMethods(c)); 
... 
private static List<Method> findMethods(Class<?> clazz) { 
    final List<Method> methods = new ArrayList<>(16); 
    while (clazz != Object.class) { 
     for (final Method method : clazz.getDeclaredMethods()) { 
      if (method.isAnnotationPresent(MyAnnotation.class)) { 
       methods.add(method); 
      } 
     } 
     clazz = clazz.getSuperclass(); 
    } 
    return methods; 
} 

:

+0

웹 응용 프로그램이 시작된 후에 주석에 대한 일회성 스캔 (스프링과 비슷 함) 일 수 있습니다. –

+0

@AndrewS 응용 프로그램 시작을 수정할 수 없습니다. – LppEdd

답변

1

자바 8에있는 경우는, 주석과 방법의 설정을 다시 계산하지 않도록 computeIfAbsent를 사용합니다.

+0

유감 스럽지만 코드베이스는 JDK 1.6 이상입니다. 나는 꽤 큰 제약이있다. – LppEdd

+0

Guava를 사용하는 경우 무제한 '캐시'를 대신 사용할 수 있습니다. –