Java-如何选择一个可用的路径来加载静态块中的文件



我的类中有一个静态块,这样当类加载器加载类定义时,就会从这个静态块中调用一个方法。该方法的目的是从一个可用路径加载配置。我希望使用第一个可用路径。

有两个配置文件(metrics_config.jsonmetrics_config_new.json(,每个配置文件都可以位于以下两个路径之一:

private static final File CONFIG_FILE_1 = new File("file:///dest1/config/metrics_config.json");
private static final File CONFIG_FILE_2 = new File("file:///dest2/config/metrics_config.json");
private static final File CONFIG_FILE_3 = new File("file:///dest1/config/metrics_config_new.json");
private static final File CONFIG_FILE_4 = new File("file:///dest2/config/metrics_config_new.json");

如何只传递一个当前可用于该方法的路径?我想这可能看起来像这样:

static {
// choose 1st file's path
if (CONFIG_FILE_1.exists() && CONFIG_FILE_1.isFile()) {
loadConfiguration(CONFIG_FILE_1);
}
if (CONFIG_FILE_2.exists() && CONFIG_FILE_2.isFile()) {
loadConfiguration(CONFIG_FILE_2);
}
// choose 2nd file's path
if (CONFIG_FILE_3.exists() && CONFIG_FILE_3.isFile()) {
loadConfiguration(CONFIG_FILE_3);
}
if (CONFIG_FILE_4.exists() && CONFIG_FILE_4.isFile()) {
loadConfiguration(CONFIG_FILE_4);
}
}

我当前解决方案的缺点是,它将同时检查第一个文件和第二个文件的路径。确定传递给loadConfiguration方法的路径的正确方法是什么?

解决这个问题的方法实际上不是这样做。不要使用static代码块或其他类初始化代码,因为IO等环境问题(而不是使用类加载器(而执行失败几率很高的操作。

还有

  • 在这样做的时候确保良好的错误处理太难了。已检查的异常(包括IOException(可能不会从中传播出去,这意味着IO代码中的所有错误处理都必须是自包含的
  • 这使得使用依赖注入的单元测试变得非常困难
  • 不同类中的static块的执行顺序并不明显,如果重构代码,可能会发生变化。这使得那些static块之间的依赖关系很难在代码复杂的情况下得到正确的。正确执行IO很复杂
  • 在保持锁定的同时执行static块。如果static块直接或间接尝试执行任何多线程,这可能会导致死锁。例如,通过使用流。避免此类问题的唯一方法是保持块中的代码非常简单。正如我之前所说,IO代码很复杂。它不可避免地以一种复杂而不明显的方式涉及到对其他类的委托(封装和信息隐藏是一个特性,而不是bug(。你能确定封装的代码中没有会导致死锁吗
  • 重要的是,在卸载相应的类加载器之前,静态对象引用不会被垃圾收集。因此,当引用是外部资源时,可能的内存泄漏可能会造成严重影响

相反,将读取的配置文件移动到main方法或从中调用的方法中。

您可以使用else if来执行以下操作:

static {
// choose 1st file's path
if (CONFIG_FILE_1.exists() && CONFIG_FILE_1.isFile()) {
loadConfiguration(CONFIG_FILE_1);
}
else if (CONFIG_FILE_2.exists() && CONFIG_FILE_2.isFile()) {
loadConfiguration(CONFIG_FILE_2);
}
// choose 2nd file's path
if (CONFIG_FILE_3.exists() && CONFIG_FILE_3.isFile()) {
loadConfiguration(CONFIG_FILE_3);
}
else if (CONFIG_FILE_4.exists() && CONFIG_FILE_4.isFile()) {
loadConfiguration(CONFIG_FILE_4);
}
}

在最好的情况下,这意味着只需要检查其中的2条路径,但在最坏的情况下仍然需要检查所有路径。

为了避免代码重复,创建一个单独的方法来获取正确的文件可能也是一个不错的主意。

public static File fetchConfigFile(file1, file2) {
if (file1.exists() && file1.isFile()) {
return file1;
}
else if (file2.exists() && file2.isFile()) {
return file2;
}
// Be aware: returning null might not be what you want. 
return null;
}

并且比static块可以简化为:

static {
loadConfiguration(fetchConfigFile(CONFIG_FILE_1, CONFIG_FILE_2));
loadConfiguration(fetchConfigFile(CONFIG_FILE_3, CONFIG_FILE_4));
}

最新更新