如何搜索带注释类的整个类路径?

我正在创建一个库,希望允许用户注释他们的类,因此当Web应用程序启动时,我需要扫描整个类路径以查找某些注释。

我正在考虑类似于Java EE 5 Web服务或EJB的新功能。你用@WebService或@EJB注释你的类,系统会在加载时找到这些类,这样就可以远程访问它们。


当前回答

如果你正在寻找一个替代反射,我想推荐Panda Utilities - AnnotationsScanner。这是一个基于反射库源代码的无Guava (Guava有~3MB, Panda Utilities有~200kb)扫描仪。

它还专门用于基于未来的搜索。如果你想扫描多次包含的源,或者甚至提供一个API,允许某人扫描当前的类路径,AnnotationsScannerProcess会缓存所有获取的类文件,所以它真的很快。

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

其他回答

反射似乎比Spring快得多。找到了解决这一差异的特性请求:http://www.opensaga.org/jira/browse/OS-738

这就是为什么在开发过程中使用reflection作为应用程序的启动时间是非常重要的。对于我的用例来说,Reflections似乎也很容易使用(找到一个接口的所有实现者)。

如果你正在寻找一个替代反射,我想推荐Panda Utilities - AnnotationsScanner。这是一个基于反射库源代码的无Guava (Guava有~3MB, Panda Utilities有~200kb)扫描仪。

它还专门用于基于未来的搜索。如果你想扫描多次包含的源,或者甚至提供一个API,允许某人扫描当前的类路径,AnnotationsScannerProcess会缓存所有获取的类文件,所以它真的很快。

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

Spring有一个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;
    }

在Spring中,您还可以使用AnnotationUtils类编写以下代码。例如:

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

要了解更多细节和所有不同的方法,请查看官方文档: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

现在回答还来得及吗? 我想说,最好使用类库,如ClassPathScanningCandidateComponentProvider或Scannotations

但即使有人想用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;

}
}

在配置文件中,放入包名并将其解编到一个类。