可伸缩地在jar中添加用于实例化的类

时间:2013-06-14 17:46:07

标签: java design-patterns reflection paradigms

我需要一些关于范式的建议。之前,我有类似的东西

package/Instantiator.class

package/instances/GenericInstance.class (abstract)

package/instances/AInstance.class (extends Generic)

package/instances/BInstance.class (extends Generic)

Instantiator所做的是搜索package/instances文件夹中的所有类文件,并使用反射对每个文件进行实例化,并在所有实例上调用抽象方法并收集输出并保存到数据库中。

但是,我现在必须将我的代码打包到一个Jar中,而Java似乎不允许在jar中的包中搜索所有类文件(因为它似乎混淆了路径)。

我可以在GenericInstance中的List中添加所有实例,然后Instantiator可以获取类列表。

但我希望其他人能够在该软件包中添加一个类,就是这样。

我应该遵循什么模式?任何代码帮助?谢谢!

2 个答案:

答案 0 :(得分:1)

JDK中有一个内置解决方案,即ServiceLoader(Java 6+)。但是,它要求用户在META-INF/services中创建一个包含实现列表的文件。

如果您的基本界面是package.instances.GenericInstance,那么您的文件将被称为META-INF/services/package.instances.GenericInstance,其内容将是:

path.to.implementation1
path.to.implementation2

等。根据您使用的构建系统,可能会自动为您生成此类文件(maven有一个插件,请参阅here)。

  

Java似乎不允许在jar中的包中搜索所有类文件

是的,它可以(但是执行它的代码非常复杂 - 你必须创建一个URLClassLoader等)。

一个解决方案,如果所有jar在运行时都在你的类路径中,那就是使用像reflections这样的东西(奖励:取决于番石榴,所以你得到它的所有细节),它有类别等的有效过滤器,以及可以“反映”除“系统”类加载器之外的类加载器;所以这也可以。

答案 1 :(得分:0)

我刚刚发现的方法:

try {    

    String jarName = new File(Insantiator.class.getProtectionDomain()    
                                                            .getCodeSource()    
                                                            .getLocation()    
                                                            .getPath())    
                                                            .getName();    
    JarFile jar = new JarFile(jarName);    
    Enumeration<JarEntry> entries = jar.entries();    
    while(entries.hasMoreElements()) {    
        ZipEntry entry = entries.nextElement();    
        String name = entry.getName();    
        if(name.contains("package/instances") && !name.contains("GenericInstance.class") && name.contains(".class")) {    
            name = name.replace("/", ".").replace(".class", "");    
            try {    
                Class theClass = Class.forName(name);    
                GenericInstance instance = (GenericInstance ) theClass.newInstance();    
                instances.add(instance);    
            } catch(InstantiationException | IllegalAccessException | ClassNotFoundException e) {    
                Utilities.writeLog("---- tried: " + name);    
                Utilities.writeLogException(null, e);    
            }    
        }    
    }        

} catch (IOException e) {    
    Utilities.writeLogException(null, e);    
}