1

I need some advice on a paradigm to follow. Before, I had something like this

package/Instantiator.class

package/instances/GenericInstance.class (abstract)

package/instances/AInstance.class (extends Generic)

package/instances/BInstance.class (extends Generic)

What Instantiator did was to search package/instances folder for all class files, and instantiated each with reflection and call an abstract method on all the instances and collected output and save to a DB.

Howver, I have to package my code in a Jar now, and Java does not seem to allow searching for all class files in a package in a jar (since it seems to mess with pathing).

I could add all instances in a List in GenericInstance or something, and then Instantiator could just get the list of classes.

But I would like for other people to just be able to add a class to that package and that's it.

What pattern should I follow here? Any code help? Thanks!

4

2 回答 2

1

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,因此您可以获得它的所有细节),它具有有效的类过滤器等,并且可以“反射”类加载器以外“系统”类加载器;所以这也可以。

于 2013-06-14T18:00:20.190 回答
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);    
}
于 2013-06-14T19:16:55.280 回答