我有一个类ConfigFactory
,它可以通过vert.x conf模块为我提供来自JSON文件的一些配置。
public class ConfigFactory {
private static JsonObject result = new JsonObject();
static {
ConfigStoreOptions fileStore = new ConfigStoreOptions()
.setType("file")
.setOptional(true)
.setFormat("json")
.setConfig(new JsonObject().put("path", "conf/config.json"));
ConfigRetrieverOptions options = new ConfigRetrieverOptions().addStore(fileStore);
ConfigRetriever retriever = ConfigRetriever.create(VertxSingleton.VERTX, options);
retriever.getConfig(ar -> {
if (ar.failed()) {
throw new RuntimeException("Config get error! Something went wring during getting the config");
} else {
result.mergeIn(ar.result());
}
});
}
public static JsonObject getHttpConfig() {
BiFunction<Integer, String, JsonObject> httpConfigFile = (port, host) -> new JsonObject()
.put("port", port).put("host", host);
if (!result.isEmpty()) {
JsonObject http = result.getJsonObject("http");
return httpConfigFile.apply(http.getInteger("port"), http.getString("host"));
} else {
throw new RuntimeException("HTTP Config get error! Something went wring during getting the config");
}
}
}
但是在Verticle中,我使用JsonObject httpConfig = ConfigFactory.getHttpConfig();
,它将给我例外
HTTP Config get error! Something went wring during getting the config
。这一次result
是空的。
我发现静态方法getHttpConfig
在静态代码块之前运行。大约一秒钟,静态代码块将运行。当时result
不为空。
你能帮我吗?谢谢!
答案 0 :(得分:3)
与其说是vertX相关问题,不如说是设计问题。当类加载器加载该类时,将执行静态块,而该静态块基本上会在首次引用该类时发生。如果您是第一次使用ConfigFactory.getHttpConfig();
进行引用,则由类加载器加载该类,并执行该静态块,并使用处理程序调用retrieveConfig。不幸的是,它没有阻止执行(处理程序等待结果),因此您立即调用了该类。因此,为了使其正常工作,应在初始化完成后调用getHttpConfig()。
一个使静态块同步的解决方案是使用Future选项。
例如:
Future<JsonObject> futureJson=ConfigRetriever.getConfigAsFuture(retriever);
JsonObject obj=futureJson.get();
在静态块中调用future.get()时,它将等到检索到配置后再继续。看起来似乎更容易理解解决方案,但我不会使用它。出于某种原因使它异步,我们不应该更改该行为。
例如:
private static JsonObject result = new JsonObject();
private static boolean readyToGo;
static {
retriever.getConfig(ar -> {
....
if (ar.failed()) {
...
} else {
result.mergeIn(ar.result());
ConfigFactory.readyToGo=true; //Now we are good to go
}
});
}
然后
public static JsonObject getHttpConfig() {
if (!readyToGo) throw Exception
}
添加一个isReady()方法,当您调用getHttpConfig()方法时,将首先调用isReady()。像这样:
while(!ConfigFactory.isReady()){
//wait ;)
}
ConfigFactory.getHttpConfig(); //it will work here
我想您可以写得更好;)但是,通常的想法是,无论对象是否准备好使用,都应维持其状态。执行静态配置并不能保证对象处于就绪状态,因此您应该自己管理该状态。