查找实现接口的Java类
前段时间,我遇到了一段代码,它使用了一些标准的Javafunction来定位实现给定接口的类。 我知道函数隐藏在一些非逻辑的地方,但是它们可以用于其他类,如包名所暗示的。 当时我不需要它,所以我忘记了,但现在我做了,我似乎无法再次findfunction。 哪里可以find这些function?
编辑:我不寻找任何IDEfunction或任何东西,而是可以在Java应用程序内执行的东西。
前一阵子,我为了做你想做的事情而组装了一个包,还有更多。 (我需要一个工具,我正在写)。 它使用ASM库。 你可以使用reflection,但ASMperformance更好。
我把我的软件包放在我网站上的开源库中。 图书馆在这里: http : //software.clapper.org/javautil/ 。 你想从ClassFinder类开始。
我为它编写的工具是RSS阅读器,我仍然每天都在使用,所以代码确实倾向于被使用。 我使用ClassFinder来支持RSS阅读器中的插件API; 在启动时,它会在几个目录树中查找包含实现特定接口的类的jar和类文件。 这比你想象的要快得多。
该库是BSD许可的,所以你可以安全地将它与你的代码捆绑在一起。 来源是可用的。
如果这对你有用,请帮助自己。
更新:如果你使用Scala,你可能会发现这个库更适合Scala。
spring可以为你做这个…
BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry(); ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr); TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class); s.addIncludeFilter(tf); s.scan("package.you.want1", "package.you.want2"); String[] beans = bdr.getBeanDefinitionNames();
注意如果你想得到正确的结果,TypeFilter很重要! 您也可以在此处使用排除filter。
Scanner可以在spring-context中find,在spring-beans中注册,而type-filter在spring-core中。
我真的很喜欢这样做的reflection库 。
它提供了许多不同types的扫描器( getTypesAnnotatedWith
, getSubTypesOf
等),并且写入或扩展自己的过程非常简单。
您正在讨论的代码听起来像ServiceLoader
,它是在Java 6中引入的,用于支持自Java 1.3或更早版本以来定义的function。 出于性能原因,这是在运行时查找接口实现的推荐方法; 如果你需要在旧版本的Java中支持这个,我希望你会发现我的实现有帮助。
在早期版本的Java中有几个这样的实现,但是在Sun软件包中,不是在核心API(我认为ImageIO内部有一些类可以实现这一点)。 由于代码很简单,我build议您提供自己的实现,而不是依赖于可能会更改的非标准Sun代码。
包级别注释
我知道这个问题很早以前就已经被回答了,但是另一个解决这个问题的方法是使用Package Level Annotations。
虽然很难去查找JVM中的所有类,但它实际上很容易浏览包层次结构。
Package[] ps = Package.getPackages(); for (Package p : ps) { MyAno a = p.getAnnotation(MyAno.class) // Recursively descend }
然后只是让你的注释有一个Class数组的参数。 然后在你的package-info.java中放入一个特定的包MyAno。
如果人们有兴趣,我会添加更多的细节(代码),但最有可能得到的想法。
MetaInf服务加载器
要添加到@erickson答案,你也可以使用服务加载器的方法。 Kohsuke有一个很好的方法来生成你需要的服务加载器方法所需的META-INF的东西:
http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html
你也可以使用可扩展组件扫描器(extcos: http ://sf.net/projects/extcos)并search所有实现如下接口的类:
Set<Class<? extends MyInterface>> classes = new HashSet<Class<? extends MyInterface>>(); ComponentScanner scanner = new ComponentScanner(); scanner.getClasses(new ComponentQuery() { @Override protected void query() { select(). from("my.package1", "my.package2"). andStore(thoseImplementing(MyInterface.class).into(classes)). returning(none()); } });
这适用于文件系统上的类,在jar中,甚至在JBoss虚拟文件系统上。 它进一步devise用于在独立的应用程序以及任何networking或应用程序容器内工作。
完全一般,这个function是不可能的。 Java ClassLoader机制仅保证能够请求具有特定名称(包括pacakge)的类,并且ClassLoader可以提供类,或者可以声明它不知道该类。
类可以(并且经常)从远程服务器加载,甚至可以在运行中构build它们; 编写一个ClassLoader并返回一个有效的类来实现给定的接口,这个ClassLoader对于你要求的任何名字来说都是不难的。 那么实现该接口的类的列表将是无限长的。
实际上,最常见的情况是一个URLClassLoader
,它在文件系统目录和JAR文件列表中查找类。 所以你需要的是获得URLClassLoader
,然后遍历这些目录和归档文件,以及你在其中find的每个类文件,请求相应的Class
对象并查看getInterfaces()
方法的返回值。
显然,Class.isAssignableFrom()告诉你一个单独的类是否实现了给定的接口。 那么问题就是获取要testing的类的列表。
据我所知,从Java没有直接的方式要求类加载器的“你可能加载类的列表”。 所以你必须通过迭代遍历可见的jar来调用Class.forName()来加载类,然后testing它。
但是,如果您只是想知道实际上已经加载的接口的实现类,它会更容易一些:
- 通过Java Instrumentation框架,您可以调用Instrumentation.getAllLoadedClasses()
- 通过reflection,您可以查询给定ClassLoader的ClassLoader.classes字段。
如果使用了检测技术,那么(如链接中所述)会发生的情况是,当JVM启动并传递一个Instrumentation对象时,就会调用“agent”类。 在这一点上,你可能想要“保存它以后”在一个静态的领域,然后让你的主要应用程序代码稍后调用它来获取加载类的列表。
如果你从一个正在运行的程序的angular度来问,那么你需要看java.lang。*包。 如果你得到一个Class对象,你可以使用isAssignableFrom方法来检查它是否是另一个Class的接口。
没有一个简单的内置search方式,像Eclipse这样的工具build立这个信息的索引。
如果您没有要testing的Class对象的特定列表,则可以查看ClassLoader对象,使用getPackages()方法构build您自己的包层次结构迭代器。
只是一个警告,虽然这些方法和类可以很慢。