我正在开发一个命令行应用程序,它在运行时加载用户指定的文本转换器(通过命令行arg提供的类文件/ jar的路径)。基本上我正在使用该参数并使用它来创建URLClassLoader。然后我需要找到实现Transable接口的URLClassloader可用的所有类。
现在我只允许这个命令行arg成为包含类文件的目录。使解决方案相当简单(下面的代码)。但老实说,我不喜欢这个解决方案,因为它破坏了jar文件,jar文件目录等等。而且,对于任何具有已定义包的类,这显然都会出现故障,因为loadClass需要包括包的全名。谁有更好的方法?
File d = new File(path);
if(d.isDirectory()) {
URL url = d.toURI().toURL();
ClassLoader cl = new URLClassLoader(new URL[]{url});
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
};
for(File f : d.listFiles(filter)) {
String name = f.getName().substring(0, f.getName().indexOf("."));
String key = "";
if(name.endsWith("Translator")) {
key = name.substring(0, name.indexOf("Translator"));
}
else if(name.endsWith("translator")) {
key = name.substring(0, name.indexOf("translator"));
}
else
key = name;
Class c = cl.loadClass(name);
if(Transable.class.isAssignableFrom(c)) {
Transable t = (Transable)c.newInstance();
env.registerTranslator(key, t);
}
else {
System.out.println("[ClassLoader] "+c.getCanonicalName()+" will not be loaded. It is not a translator class");
}
}
}
else {
throw new Error("NOT IMPLEMENTED");
}
答案 0 :(得分:4)
如果你沿着这条路继续下去,你可能只需要暴力。据我所知,默认的类加载器甚至不会将类加载到JVM中,除非以某种方式引用它。这意味着,除非您知道要加载它们的完全限定类名,否则您的某些类基本上是不可见的。
您可能需要重新考虑您的要求。因为加载一组Translators会更容易,因为你已经为它们提供了类名。
答案 1 :(得分:4)
不应该显式地搜索实现者,而应该使用Java的服务提供者接口(SPI)和ServiceLoader类(在Java 6中引入)。 SPI是用Java完成的一种标准方法。
请参阅official Java tutorial,了解如何在运行时使用ServiceLoader创建服务提供程序以及如何使用它。
答案 2 :(得分:3)
这可能符合法案。如果没有,你应该能够查看他们的来源,以了解什么对你有用。 http://code.google.com/p/reflections/
答案 3 :(得分:3)
原则上,这对任意类加载器都不起作用,因为它们可以使用任何可以想象的方式来实际加载类,而根本没有任何“目录监听”功能。
每当loadClass
出现时,类加载器甚至可以动态生成类(即类的字节码),并想象一个TransableClassloader,其中每个这样自动定义的类将实现您的接口 - 您的程序永远不会结束。
也就是说,对于URLClassloader
,您可以使用getURLs()
,对于jar:
和file:
网址,您可以使用JarFile
或{{1 api获取要尝试的文件名列表(以及类名)。由于您拥有URL中给出的包层次结构的根,因此找到正确的包名称并不困难。
(如果您需要更多细节,请说出来。)
编辑:对于包名称,它们对应于层次结构内的目录名称。因此,当您有一个与(例如)File
对应的基本网址,并找到名为dir/classes
的类文件时,它对应于类dir/classes/com/company/gui/SimpleTranslator.class
。
因此,删除基本前缀并将com.company.gui.SimpleTranslator
替换为/
(以及.
的剪切)。 (在JarFile中,您不必删除前缀。)
实际上,如果使用递归方法遍历文件层次结构,则可以使用相同的方法构建package-name,只需附加字符串(将它们作为参数提供给下一个递归调用):
.class
答案 4 :(得分:0)
这会有帮助吗?
由于Class c = cl.loadClass(name);
类方法getInterfaces()返回一个类数组
检查每个班级名称是否与译员班级名称匹配。