문제

주석이 달린 클래스의 전체 클래스 경로를 검색하는 가장 좋은 방법은 무엇입니까?

나는 라이브러리를 만들고 있으며 사용자가 자신의 클래스에 주석을 달 수 있도록 허용하고 싶습니다. 따라서 웹 애플리케이션이 시작될 때 특정 주석에 대해 전체 클래스 경로를 스캔해야 합니다.

이를 수행할 수 있는 라이브러리나 Java 시설을 알고 계십니까?

편집하다:저는 Java EE 5 웹 서비스 또는 EJB의 새로운 기능과 같은 것에 대해 생각하고 있습니다.당신은 수업에 주석을 달았습니다. @WebService 또는 @EJB 시스템은 로드하는 동안 이러한 클래스를 찾아 원격으로 액세스할 수 있습니다.

도움이 되었습니까?

해결책

사용 org.springframework.context.annotation.classPathScanningCandIteComponentProvider

API

기본 패키지에서 클래스 경로를 스캔하는 구성 요소 제공자. 그런 다음 후보자를 찾기 위해 결과 클래스에 제외 및 필터를 포함시킵니다.

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());

다른 팁

그리고 또 다른 해결책은입니다 Google 반사.

빠른 검토:

  • 스프링 솔루션은 스프링을 사용하는 경우가는 길입니다. 그렇지 않으면 큰 의존성입니다.
  • ASM을 직접 사용하는 것은 약간 번거 롭습니다.
  • Java Assist를 직접 사용하는 것도 어리석은 일입니다.
  • Annovention은 매우 가볍고 편리합니다. 아직 Maven 통합이 없습니다.
  • Google 반사가 Google 컬렉션을 가져옵니다. 모든 것을 색인화 한 다음 매우 빠릅니다.

다음을 사용하여 특정 주석이 있는 클래스를 찾을 수 있습니다. 클래스 그래프, 관심 있는 다른 기준을 검색할 수도 있습니다.주어진 인터페이스를 구현하는 클래스.(면책조항, 저는 ClassGraph의 저자입니다.) ClassGraph는 메모리, 클래스 경로의 모든 클래스 또는 화이트리스트에 등록된 패키지를 사용하면 원하는 대로 해당 클래스 그래프를 쿼리할 수 있습니다.클래스그래프는 지원합니다 더 많은 클래스 경로 사양 메커니즘 및 클래스 로더 다른 어떤 스캐너보다 뛰어나며 새로운 JPMS 모듈 시스템과도 원활하게 작동하므로 ClassGraph를 기반으로 코드를 작성하면 코드 이식성이 극대화됩니다. 여기에서 API를 참조하세요.

당신이 정말로 원한다면 가벼운 무게 (의존성 없음, 간단한 API, 15 kb JAR 파일) 및 매우 빠릅니다 해결책을 살펴보십시오 annotation-detector 발견되었습니다 https://github.com/rmuller/infomas-asl

면책 조항 : 저는 저자입니다.

Java Pluggable Annotation Processing API를 사용하여 컴파일 프로세스 중에 실행될 주석 프로세서를 작성하고 모든 주석이 달린 클래스를 수집하고 런타임 사용을 위해 인덱스 파일을 빌드 할 수 있습니다.

이것은 런타임에 클래스 경로를 스캔 할 필요가 없기 때문에 주석이 달린 클래스 검색을 수행 할 수있는 가장 빠른 방법입니다. 이는 일반적으로 매우 느리게 작동합니다. 또한이 접근 방식은 모든 클래스 로더와 함께 작동하며 일반적으로 런타임 스캐너가 지원하는 UrlClassLoader와 함께 작동합니다.

위의 메커니즘은 이미 구현되었습니다 ClassIndex 도서관.

사용하려면 사용자 정의 주석에 주석을 달 수 있습니다 @IndExAnnotated 메타 공장. 이렇게하면 컴파일 시간에 인덱스 파일이 생성됩니다. Meta-Inf/annotations/com/test/yourcustomannotation 모든 주석이 붙은 클래스를 나열합니다. 실행을 통해 런타임에 인덱스를 액세스 할 수 있습니다.

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

노력하다 규칙.

특정 주석에 대해 클래스 경로 또는 웹 응용 프로그램 Lib 디렉토리를 검색하는 데 사용할 수 있습니다.

사용하고 싶을 수도 있습니다 http://code.google.com/p/annovention/

Spring을 사용하면 AnnotationUtils 클래스를 사용하여 다음을 작성할 수도 있습니다. 즉:

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

자세한 내용 및 모든 다른 방법은 공식 문서를 확인하십시오.https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/annotationutils.html

약간의 외상이지만 Spring은 또한 비슷한 일을합니다. u003Ccontext:component-scan>, 어떤 소스 코드를 연구 할 수 있습니까?

Spring은 '고정 관념'클래스를 자동으로 감지 할 수있는 기능을 제공합니다 [...]. 이러한 클래스를 자동으로 설정하고 해당 콩을 등록하려면 [컨텍스트 : 구성 요소 스캔 요소]를 포함해야합니다.

대답하기에는 너무 늦었습니까? 나는 다음과 같은 도서관을 옆으로가는 것이 더 낫다고 말할 것이다. ClassPathScanningCandidAteComponentProvider 또는 좋아요 경고

그러나 누군가가 클래스 로더로 손에 손을 대고 싶어서도 패키지의 수업에서 주석을 인쇄하기 위해 스스로 글을 썼습니다.

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

그리고 구성 파일에서 패키지 이름을 넣고 클래스에 해소되지 않습니다.

클래스 로더 API에는 "열거 된"방법이 없습니다. 클래스 로딩은 "주문형"활동이기 때문에 일반적으로 클래스 경로에 수천 개의 클래스가 있으며 그 중 일부는 필요합니다 (Rt.jar 요즘 혼자 48MB입니다!).

그래서, 당신도 ~할 수 있었다 모든 클래스를 열거하면 매우 시간과 메모리 소비가 될 것입니다.

간단한 접근 방식은 해당 클래스를 설정 파일에 나열하는 것입니다 (XML 또는 Fancy에 적합). 이 작업을 자동으로 수행하려면 하나의 항아리 또는 하나의 클래스 디렉토리로 제한하십시오.

그것이 당신에게 도움이 될지 확실하지 않지만, 당신은 Apache Commons-Discovery 프로젝트를 살펴볼 수 있습니다.

발견 프로젝트

Google 반사 봄보다 훨씬 빠른 것 같습니다. 이 차이점을 연주하는이 기능 요청을 발견했습니다. http://www.opensaga.org/jira/browse/os-738

이것은 응용 프로그램의 시작 시간이 개발 중에 정말로 중요하기 때문에 반사를 사용하는 이유입니다. 반사는 또한 내 사용 사례에 사용하기가 매우 쉽습니다 (인터페이스의 모든 구현 자 찾기).

대안을 찾고 있다면 반사 추천하고 싶습니다 팬더 유틸리티 - 주석 스 캐너. Guava가 없습니다 (Guava에는 ~ 3MB가 있으며 Panda Utilities에는 ~ 200kb가 있습니다. ~ 200kb) 스캐너는 반사 라이브러리 소스 코드를 기반으로합니다.

또한 미래 기반 검색을 위해 전용입니다. 여러 번 스캔하려면 소스를 포함 시키거나 API를 제공하시면 누군가 Crossplate를 스캔 할 수 있습니다. AnnotationsScannerProcess 모두 캐시를 가져옵니다 ClassFiles, 정말 빠릅니다.

간단한 예 AnnotationsScanner 용법:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);

Google 반사 인터페이스를 발견하려면

ClassPathScanningCandidateComponentProvider 인터페이스를 발견하지 않습니다.

봄에는 a라는 것이 있습니다 AnnotatedTypeScanner 수업.
이 수업은 내부적으로 사용합니다

ClassPathScanningCandidateComponentProvider

이 클래스에는 실제 스캔 코드가 있습니다. 클래스 경로 자원. 런타임에 사용 가능한 클래스 메타 데이터를 사용하여이를 수행합니다.

이 클래스를 확장하거나 동일한 클래스를 사용하여 스캔 할 수 있습니다. 아래는 생성자 정의입니다.

/**
     * Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
     * 
     * @param considerInterfaces whether to consider interfaces as well.
     * @param annotationTypes the annotations to scan for.
     */
    public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {

        this.annotationTypess = Arrays.asList(annotationTypes);
        this.considerInterfaces = considerInterfaces;
    }

스칼라 라이브러리를 원한다면 Sclasner를 사용하십시오.https://github.com/ngocdaothanh/sclasner

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top