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

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

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


当前回答

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

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

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

其他回答

如果你想要一个真正轻量级(没有依赖,简单的API, 15 kb的jar文件)和非常快速的解决方案,可以看看https://github.com/rmuller/infomas-asl上的注释检测器

声明:我是作者。

You can find classes with any given annotation with ClassGraph, as well as searching for other criteria of interest, e.g. classes that implement a given interface. (Disclaimer, I am the author of ClassGraph.) ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in whitelisted packages, and you can query that class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.

现在回答还来得及吗? 我想说,最好使用类库,如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;

}
}

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

Classloader API没有“枚举”方法,因为类加载是一个“按需”活动——在类路径中通常有数千个类,其中只有一小部分是需要的(目前仅rt.jar就有48MB !)

因此,即使您可以枚举所有的类,这也会非常耗费时间和内存。

简单的方法是在设置文件(xml或任何适合你的文件)中列出相关的类;如果您希望自动执行此操作,请将自己限制在一个JAR或一个类目录中。

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

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