如果在引用类之前未调用静态初始化程序,则如何注册java类

Ago*_*noX 9 java factory-method static-initializer

我有一个由执行文件处理的类实现的接口,比如搜索或其他什么.

public interface FileProcessorInterface {

    public void processFile(String fileName);

}
Run Code Online (Sandbox Code Playgroud)

然后我对每种文件类型都有不同的实现:

public class TxtProcessor implements FileProcessorInterface {

    @Override public void processFile(String fileName) { //do the work }

}
Run Code Online (Sandbox Code Playgroud)

因此我有处理器的Utilizer,它有一个允许注册每个类的方法,如下所示:

class Utilizer {

Map <String, Class> registered = new HashMap<>();

public void registerClass(String fileExt, Class clazz) {

    registered.put(fileExt, clazz);

}

public void processFile(String fileName) {

    //1) get the registered class from registered map (omitted because easy and not relevant)

    //2) create an instance of the class using reflection (omitted because easy and not relevant)
    FileProcessorInterface p = ....

    p.processFile(fileName);             

}
Run Code Online (Sandbox Code Playgroud)

到目前为止还可以.

现在,我提供了许多我的界面实现.

我很想为每个实现类提供一个静态初始化程序,它在Utilizer中注册自己,在我之前的TxtProcessor的情况下,它将是:

class TxtProcessor implements FileProcessorInterface {

    //previous code

    static {
        Utilizer.registerClass("txt", TxtProcessor.class);
    }

}
Run Code Online (Sandbox Code Playgroud)

问题是永远不会调用这个静态方法,因为在应用程序的"静态可达"代码中没有对我的TxtProcessor类的引用,因为它是通过反射实例化的.所以jvm不会调用静态初始化器.

假设我有两个部分:"通用代码",即Utilizer,另一方面是实现; 它必须被认为是在dinamically提供的东西,因此Utilizer部分不知道它.
事实上,这个想法恰恰相反,每个类都会注册自己而不使用Utilizer.
我很难设想一个解决方案,它不会在Utilizer端提供某种形式的"知识"实现(并且保持简单),只是因为没有调用静态初始化器的问题.怎么克服这个?

Pet*_*rey 5

你可以看一下Reflections库.它允许您查找实现接口,具有注释或扩展类的所有类.


Rav*_*yal 5

在这里使用反射似乎是最合适的。这就像是为了做到这一点。

所有你需要的是一个小Utilizer

static {

    Reflections reflections = new Reflections(
                new ConfigurationBuilder()
               .setUrls(ClasspathHelper.forPackage("path.to.all.processors.pkg"))
               .setScanners(new SubTypesScanner())
           );

    reflections.getSubTypesOf(path.to.all.processors.pkg.FileProcessor.class);
}
Run Code Online (Sandbox Code Playgroud)

如果您不想要第三方依赖项,只需将FileProcessors.properties文件添加到您的类路径

txt=path.to.all.processors.pkg.TxtProcessor
doc=path.to.all.processors.pkg.DocProcessor
pdf=path.to.all.processors.pkg.PdfProcessor
Run Code Online (Sandbox Code Playgroud)

然后将所有列出的类注册Utilizer

static {
    Properties processors = new Properties();
    try {
        processors.load(Utilizer.class
                  .getResourceAsStream("FileProcessors.properties"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    for (String ext : processors.stringPropertyNames()) {
        Utilizer.registerClass(ext, Class.forName(processors.getProperty(ext));
    }
}
Run Code Online (Sandbox Code Playgroud)

这不再需要每次都使用静态FileProcessor