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



我需要一些关于遵循范例的建议。之前,我有这样的东西

package/Instantiator.class

package/instances/GenericInstance.class (abstract)

package/instances/AInstance.class (extends Generic)

package/instances/BInstance.class (extends Generic)

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

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

我可以在GenericInstance或其他东西的List中添加所有实例,然后Instantiator可以获得类的列表。

但是我希望其他人能够在那个包中添加一个类,仅此而已。

我应该遵循什么模式呢?有什么代码帮助吗?谢谢!

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

如果你的基本接口是package.instances.GenericInstance,那么你的文件将被称为META-INF/services/package.instances.GenericInstance,它的内容将是:

path.to.implementation1
path.to.implementation2

等。根据您使用的构建系统,这种文件可能会自动生成(maven有一个插件,见这里)。

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

是的,它可以(但要做到这一点的代码是相当复杂的-你必须创建一个URLClassLoader等)。

一个解决方案,如果所有的jar在运行时都在你的类路径中,是使用类似反射的东西(奖励:依赖于Guava,所以你得到了它的所有细节),它对类等有有效的过滤器,可以"反射"类加载器而不是"系统"类加载器;

我刚刚发现的方法:

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

最新更新