IT이야기

런타임에 Java 주석 검색

cyworld 2022. 6. 22. 22:08
반응형

런타임에 Java 주석 검색

전체 클래스 경로에서 주석이 달린 클래스를 검색하려면 어떻게 해야 합니까?

라이브러리를 만들고 있는데 사용자가 클래스에 주석을 달 수 있도록 허용하고 싶기 때문에 웹 응용 프로그램이 시작되면 클래스 경로 전체를 스캔하여 특정 주석을 찾아야 합니다.

Java EE 5 Web Services ( EJB ) 。을 붙입니다.@WebService ★★★★★★★★★★★★★★★★★」@EJB시스템은 로드 중에 이러한 클래스를 발견하여 원격으로 액세스할 수 있습니다.

org.springframework.context.annotation을 사용합니다.ClassPathScanningCandidateComponentProvider

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());

또 다른 해결책은 Ronmamo의 Reflections입니다.

퀵 리뷰:

  • Spring을 사용한다면 Spring 솔루션이 가장 적합합니다.그렇지 않으면 큰 의존관계가 됩니다.
  • ASM을 직접 사용하는 것은 조금 번거롭습니다.
  • Java Assist를 직접 사용하는 것도 어색합니다.
  • Annovation은 초경량이고 편리합니다.메이븐 통합은 아직 없습니다.
  • 반사는 모든 것을 색인화하고 나서 매우 빠릅니다.

ClassGraph를 사용하여 특정 주석을 가진 클래스를 찾을 수 있을 뿐만 아니라 특정 인터페이스를 구현하는 클래스 등 관심 있는 다른 기준을 검색할 수 있습니다. (해당사자, 저는 ClassGraph의 작성자입니다.)ClassGraph는 전체 클래스 그래프(모든 클래스, 주석, 메서드, 메서드 매개 변수 및 필드)를 메모리, 클래스 경로의 모든 클래스 또는 화이트리스트 패키지의 클래스에 대해 추상적으로 표현할 수 있으며 원하는 방식으로 클래스 그래프를 쿼리할 수 있습니다.ClassGraph는 다른 어떤 스캐너보다 더 많은 클래스 경로 지정 메커니즘과 클래스 로더를 지원하며 새로운 JPMS 모듈 시스템과 심리스하게 작동하기 때문에 ClassGraph를 기반으로 코드를 사용하면 최대한으로 휴대할 수 있습니다.API를 참조하십시오.

매우 가벼운 무게(의존관계 없음, 단순한 API, 15kb jar 파일)와 매우 빠른 솔루션을 원하는 경우 다음을 참조하십시오.annotation-detectorhttps://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)

zapp의 훌륭한 코멘트가 이 모든 답변에 반영되어 있습니다.

new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)

에는 봄이라는 .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;
    }

대답하기엔 너무 늦었나요?ClassPathScanningCandidateComponentProviderScannotations와 같은 라이브러리를 사용하는 것이 좋습니다.

하지만 classLoader를 사용해 보고 싶은 사람도 있지만, 저는 수업의 주석을 패키지로 인쇄하기 위해 직접 몇 개를 썼습니다.

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;

}
}

또한 config File에서 패키지 이름을 입력하고 클래스로 마찰을 해제합니다.

Classloader API에는 "enumerate" 메서드가 없습니다.클래스 로딩은 "on-demand" 액티비티이기 때문입니다.일반적으로 클래스 패스에 필요한 클래스는 수천 개뿐입니다(rt.jar만 현재 48MB!).

따라서 모든 클래스를 열거할 수 있더라도 이 작업은 시간과 메모리가 많이 소요됩니다.

간단한 방법은 관련 클래스를 셋업 파일(xml 또는 원하는 것)에 나열하는 것입니다.이 작업을 자동으로 수행하려면 1개의 JAR 또는1개의 클래스 디렉토리로 제한합니다.

스프링을 사용하면 AnnotationUtils 클래스를 사용하여 다음과 같이 쓸 수도 있습니다.

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

자세한 내용 및 모든 방법에 대해서는http://https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html 를 참조해 주세요.

인터페이스를 검색하려면 Google Reflection을 클릭하십시오.

ClassPathScanningCandidateComponentProvider는 인터페이스를 검출하고 있지 않습니다.

구글 리플리테이션이 스프링보다 훨씬 빠른 것 같다.이 차이를 해결하는 기능 요청을 발견했습니다.http://www.opensaga.org/jira/browse/OS-738

개발 중에 앱 부팅 시간이 매우 중요하기 때문에 Reflections를 사용해야 하는 이유입니다.리플렉션도 매우 사용하기 쉬운 것 같습니다(인터페이스의 모든 실장자를 찾습니다).

만약 당신이 반사에 대한 대안을 찾고 있다면 는 Panda Utilities - AnnotationsScanner를 추천하고 싶다.리플렉션 라이브러리 소스코드에 근거해, Guava 프리(Guava는 3MB까지, Panda Utilities는 200kb까지) 스캐너입니다.

또한 미래 기반 검색 전용입니다.포함된 소스를 여러 번 스캔하거나 현재 클래스 경로를 스캔할 수 있는 API를 제공하려는 경우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);

언급URL : https://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime

반응형