如何使用番石榴在 GWT 中缓存服务器结果?
How to cache server results in GWT with guava?
在我的 GWT 应用程序中,我经常多次引用相同的服务器结果。我也不知道先执行哪个代码。因此,我想使用异步(客户端)结果的缓存。
我想使用现有的缓存库;我正在考虑 guava-gwt.
我找到了这个 Guava 同步 缓存示例(在 guava's documentation 中):
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
这就是我尝试使用 Guava 缓存的方式异步(我不知道如何进行这项工作):
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
// I want to do something asynchronous here, I cannot use Thread.sleep in the browser/JavaScript environment.
service.createExpensiveGraph(key, new AsyncCallback<Graph>() {
public void onFailure(Throwable caught) {
// how to tell the cache about the failure???
}
public void onSuccess(Graph result) {
// how to fill the cache with that result???
}
});
return // I cannot provide any result yet. What can I return???
}
});
GWT 缺少默认 JRE 中的许多 类(特别是关于线程和并发)。
如何使用 guava-gwt 缓存异步结果?
如果只是需要缓存异步调用的结果,可以去
Non-Loading缓存,而不是加载缓存
在这种情况下,您需要使用 put、getIfPresent 方法从缓存中存储和检索记录。
String v = cache.getIfPresent("one");
// returns null
cache.put("one", "1");
v = cache.getIfPresent("one");
// returns "1"
或者,可以在缓存未命中时从 Callable 加载新值
String v = cache.get(key,
new Callable<String>() {
public String call() {
return key.toLowerCase();
}
});
进一步参考:https://guava-libraries.googlecode.com/files/JavaCachingwithGuava.pdf
据我了解,您想要实现的不仅是异步缓存,而且是惰性缓存,要创建异步缓存,GWT 不是最佳选择,因为在使用客户端异步实现 GWT 应用程序时存在大问题执行,因为 GWT 缺少 Future
s and/or Rx 组件的客户端实现(仍然有一些 GWT 的 RxJava 实现)。所以通常 java 你想创建的东西可以通过 :
实现
LoadingCache<String, Future<String>> graphs = CacheBuilder.newBuilder().build(new CacheLoader<String, Future<String>>() {
public Future<String> load(String key) {
ExecutorService service = Executors.newSingleThreadExecutor();
return service.submit(()->service.createExpensiveGraph(key));
}
});
Future<String> value = graphs.get("Some Key");
if(value.isDone()){
// This will block the execution until data is loaded
String success = value.get();
}
但是由于 GWT 没有 Future
的实现,您需要像
一样创建一个
public class FutureResult<T> implements AsyncCallback<T> {
private enum State {
SUCCEEDED, FAILED, INCOMPLETE;
}
private State state = State.INCOMPLETE;
private LinkedHashSet<AsyncCallback<T>> listeners = new LinkedHashSet<AsyncCallback<T>>();
private T value;
private Throwable error;
public T get() {
switch (state) {
case INCOMPLETE:
// Do not block browser so just throw ex
throw new IllegalStateException("The server response did not yet recieved.");
case FAILED: {
throw new IllegalStateException(error);
}
case SUCCEEDED:
return value;
}
throw new IllegalStateException("Something very unclear");
}
public void addCallback(AsyncCallback<T> callback) {
if (callback == null) return;
listeners.add(callback);
}
public boolean isDone() {
return state == State.SUCCEEDED;
}
public void onFailure(Throwable caught) {
state = State.FAILED;
error = caught;
for (AsyncCallback<T> callback : listeners) {
callback.onFailure(caught);
}
}
public void onSuccess(T result) {
this.value = result;
state = State.SUCCEEDED;
for (AsyncCallback<T> callback : listeners) {
callback.onSuccess(value);
}
}
}
您的实施将变成:
LoadingCache<String, FutureResult<String>> graphs = CacheBuilder.newBuilder().build(new CacheLoader<String, FutureResult<String>>() {
public FutureResult<String> load(String key) {
FutureResult<String> result = new FutureResult<String>();
return service.createExpensiveGraph(key, result);
}
});
FutureResult<String> value = graphs.get("Some Key");
// add a custom handler
value.addCallback(new AsyncCallback<String>() {
public void onSuccess(String result) {
// do something
}
public void onFailure(Throwable caught) {
// do something
}
});
// or see if it is already loaded / do not wait
if (value.isDone()) {
String success = value.get();
}
当使用 FutureResult
时,您不仅会缓存执行,还会有某种惰性,因此您可以在数据加载到缓存中时显示一些 loading screen
。
在我的 GWT 应用程序中,我经常多次引用相同的服务器结果。我也不知道先执行哪个代码。因此,我想使用异步(客户端)结果的缓存。
我想使用现有的缓存库;我正在考虑 guava-gwt.
我找到了这个 Guava 同步 缓存示例(在 guava's documentation 中):
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
这就是我尝试使用 Guava 缓存的方式异步(我不知道如何进行这项工作):
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
// I want to do something asynchronous here, I cannot use Thread.sleep in the browser/JavaScript environment.
service.createExpensiveGraph(key, new AsyncCallback<Graph>() {
public void onFailure(Throwable caught) {
// how to tell the cache about the failure???
}
public void onSuccess(Graph result) {
// how to fill the cache with that result???
}
});
return // I cannot provide any result yet. What can I return???
}
});
GWT 缺少默认 JRE 中的许多 类(特别是关于线程和并发)。
如何使用 guava-gwt 缓存异步结果?
如果只是需要缓存异步调用的结果,可以去 Non-Loading缓存,而不是加载缓存
在这种情况下,您需要使用 put、getIfPresent 方法从缓存中存储和检索记录。
String v = cache.getIfPresent("one");
// returns null
cache.put("one", "1");
v = cache.getIfPresent("one");
// returns "1"
或者,可以在缓存未命中时从 Callable 加载新值
String v = cache.get(key,
new Callable<String>() {
public String call() {
return key.toLowerCase();
}
});
进一步参考:https://guava-libraries.googlecode.com/files/JavaCachingwithGuava.pdf
据我了解,您想要实现的不仅是异步缓存,而且是惰性缓存,要创建异步缓存,GWT 不是最佳选择,因为在使用客户端异步实现 GWT 应用程序时存在大问题执行,因为 GWT 缺少 Future
s and/or Rx 组件的客户端实现(仍然有一些 GWT 的 RxJava 实现)。所以通常 java 你想创建的东西可以通过 :
LoadingCache<String, Future<String>> graphs = CacheBuilder.newBuilder().build(new CacheLoader<String, Future<String>>() {
public Future<String> load(String key) {
ExecutorService service = Executors.newSingleThreadExecutor();
return service.submit(()->service.createExpensiveGraph(key));
}
});
Future<String> value = graphs.get("Some Key");
if(value.isDone()){
// This will block the execution until data is loaded
String success = value.get();
}
但是由于 GWT 没有 Future
的实现,您需要像
public class FutureResult<T> implements AsyncCallback<T> {
private enum State {
SUCCEEDED, FAILED, INCOMPLETE;
}
private State state = State.INCOMPLETE;
private LinkedHashSet<AsyncCallback<T>> listeners = new LinkedHashSet<AsyncCallback<T>>();
private T value;
private Throwable error;
public T get() {
switch (state) {
case INCOMPLETE:
// Do not block browser so just throw ex
throw new IllegalStateException("The server response did not yet recieved.");
case FAILED: {
throw new IllegalStateException(error);
}
case SUCCEEDED:
return value;
}
throw new IllegalStateException("Something very unclear");
}
public void addCallback(AsyncCallback<T> callback) {
if (callback == null) return;
listeners.add(callback);
}
public boolean isDone() {
return state == State.SUCCEEDED;
}
public void onFailure(Throwable caught) {
state = State.FAILED;
error = caught;
for (AsyncCallback<T> callback : listeners) {
callback.onFailure(caught);
}
}
public void onSuccess(T result) {
this.value = result;
state = State.SUCCEEDED;
for (AsyncCallback<T> callback : listeners) {
callback.onSuccess(value);
}
}
}
您的实施将变成:
LoadingCache<String, FutureResult<String>> graphs = CacheBuilder.newBuilder().build(new CacheLoader<String, FutureResult<String>>() {
public FutureResult<String> load(String key) {
FutureResult<String> result = new FutureResult<String>();
return service.createExpensiveGraph(key, result);
}
});
FutureResult<String> value = graphs.get("Some Key");
// add a custom handler
value.addCallback(new AsyncCallback<String>() {
public void onSuccess(String result) {
// do something
}
public void onFailure(Throwable caught) {
// do something
}
});
// or see if it is already loaded / do not wait
if (value.isDone()) {
String success = value.get();
}
当使用 FutureResult
时,您不仅会缓存执行,还会有某种惰性,因此您可以在数据加载到缓存中时显示一些 loading screen
。