2012-07-30 64 views
2

我正在考虑引入某种缓存机制(如HTML5本地存储)以尽可能避免频繁的RPC调用。我想获得有关如何在下面的代码块中引入缓存而不改变体系结构(如使用gwt-dispatch)的反馈。我能想到的来处理这个为GWT RPC异步调用启用缓存

void getData() { 

    /* Loading indicator code skipped */ 

    /* Below is a gwt-maven plugin generated singleton for SomeServiceAsync */ 
    SomeServiceAsync.Util.getInstance().getDataBySearchCriteria(searchCriteria, new AsyncCallback<List<MyData>>() { 

     public void onFailure(Throwable caught) { 
      /* Loading indicator code skipped */ 
      Window.alert("Problem : " + caught.getMessage()); 
     } 

     public void onSuccess(List<MyData> dataList) { 
      /* Loading indicator code skipped */ 
     } 
    }); 
} 

一种方法是有一个自定义MyAsyncCallback类中定义的onSuccess/onFailure处方法,然后做这样的事情 -

void getData() { 

    AsyncCallback<List<MyData>> callback = new MyAsyncCallback<List<MyData>>; 

    // Check if data is present in cache 
    if(cacheIsPresent) 
     callback.onSuccess(dataRetrievedFromCache); 
    else 
    // Call RPC and same as above and of course, update cache wherever appropriate 
} 
从这个

除此之外,我有一个更多的问题。 LocalStorage适用于流行浏览器的最大存储容量是多少?浏览器如何管理LocalStorage以适用于不同的应用程序/ URL?任何指针将不胜感激。

回答

2

我建议添加一个处理缓存的delegate class。代表类可能如下所示:

public class Delegate { 

    private static SomeServiceAsync service = SomeServiceAsync.Util.getInstance(); 

    private List<MyData> data; 

    public static void getData(Callback callback) { 
    if (date != null) { 
     callback.onSuccess(data); 
    } else { 
     service.getData(new Callback() { 
     public onSuccess(List<MyData> result) { 
      data = result; 
      callback.onSuccess(result); 
     }); 
    } 
    } 

} 

当然,这是一个粗略的示例,您必须完善代码以使其可靠。

1

我花了很长时间来决定使用散列映射来缓存结果。

我的策略是不使用单例散列表,而是存储缓存的静态实例的单例公共对象类。我没有看到加载具有过多级别的hashtree分支的单个hashmap的原因。

降低哈希分辨率

的金额。如果我知道,我处理的对象是员工,地址,项目,我将创建三个静态哈希

final static private Map<Long, Employee> employeeCache = 
    new HashMap<Long, Employee>(); 
final static private Map<Long, Address> addressCache = 
new HashMap<Long, Address>(); 
final static private Map<String name, Project> projectCache = 
new HashMap<String name, Project>(); 

public static void putEmployee(Long id, Employee emp){ 
    employeeCache.put(id, emp); 
} 
public static Employee getEmployee(Long id){ 
    return employeeCache.get(id); 
} 

public static void putEmployee(Long id, Address addr){ 
    addressCache.put(id, addr); 
} 
public static Address getEmployee(Long id){ 
    return addressCache.get(id); 
} 

public static void putProject(String name, Address addr){ 
    projectCache.put(name, addr); 
} 
public static Address getProject(String name){ 
    return projectCache.get(name); 
} 

把它全部一张地图会很毛茸茸。有效访问和存储数据的原则是 - 您确定的关于数据的信息越多,就越应该利用您拥有的信息来分离数据。它会降低访问数据所需的散列分辨率级别。更不用说所有需要完成的风险和不确定类型的演员。

避免散列如果你能

如果你知道你总是有CurrentEmployee和NextEmployee, 避免将其储存在员工的哈希值的一个值。只需创建静态实例

Employee CurrentEmployee, NextEmployee; 

这样可以避免需要任何散列分辨率。

避免污染全局命名空间

如果可能的话,让他们为类的实例,而不是静态的情况下,为了避免污染全局命名空间。

为什么要避免污染全局命名空间?因为,由于全局名称空间混淆,多于一个类会无意中使用相同的名称,导致无数的错误。

保持高速缓存最近的地方,预计或使用

如果可能的话,如果缓存主要是针对某一类,保持高速缓存为类中的一个类实例。并为其他类需要从该缓存中获取数据的罕见实例提供事件总线事件。

所以,你将有一个可预期的模式

ZZZManager.getZZZ(id); 

敲定如果可能的话缓存,

否则/并提供推杆和getter私有化了。不要让另一个类无意中重新实例化缓存,特别是如果有一天你的类变成了一个通用实用程序库。另外,推杆和getter有机会验证请求,以避免请求消除缓存或通过直接使用缓存无法处理的键或值直接呈现缓存将应用程序推入Exception。

把这些原则为JavaScript本地存储

GWT的页面说

明智地使用命名约定的可以处理存储数据的帮助。例如,在名为MyWebApp的Web应用程序中,与名为Stock的UI表中的行关联的键值数据可能具有以MyWebApp.Stock为前缀的键名称。

因此,补充你们班的HashMap,用比较简陋代码,

public class EmployeePresenter { 
    Storage empStore = Storage.getLocalStorageIfSupported(); 
    HashMap<Long, Employee> employeeCache; 

    public EmployeePresenter(){ 
    if (empStore==null) { 
     employeeCache = new HashMap<Employee>(); 
    } 
    } 

    private String getPrefix(){ 
    return this.getClass()+".Employee"; 
    //return this.getClass().getCanonicalName()+".Employee"; 
    } 

    public Employee putEmployee(Long id, Employee employee) 
    if (empStore==null) { 
     stockStore.setItem(getPrefix()+id, jsonEncode(employee)); 
     return; 
    } 
    employeeCache.put(id, employee); 
    } 

    public Employee getEmployee(Long id) 
    if (empStore==null) { 
     return (Employee) jsonDecode(Employee.class, stockStore.getItem(getPrefix()+id)); 
    } 
    return employeeCache(id); 
    } 
} 

因为,在localstore是基于字符串而已,我假设你会写自己的JSON编码解码器。另一方面,为什么不在收到回调的时候直接将json写入商店呢?

内存限制?

我不能说这个问题的专业知识,但我预测hashmaps的答案是浏览器上操作系统限制的最大内存。减去浏览器已经消耗的所有内存,插件和JavaScript等等。 。

对于HTML5本地存储的GWT页说

“的localStorage:每浏览应用程序5MB根据HTML5规范,在需要时可以将此限制增加了用户;然而,只有少数的浏览器支持此“。

“的sessionStorage:只有通过系统内存限制”由于您使用GWT-dispath这里一个简单的解决方案是缓存GWT-调度响应对象

+0

HTML5本地存储在常规浏览器缓存中保存的数据以字符串形式加密。这不是安全的存储。它不应该用于敏感数据,如社会安全号码,信用卡号码,登录凭证等等。 – 2012-07-30 07:06:53

0

agains请求对象作为一个地图的关键。它易于实现和类型不可知。您将需要重写Request-equals()方法以查看请求是否已经在缓存中。如果是,则返回缓存的响应,否则通过调用访问服务器。

IMO - localStorage的是这里不是必要的,如果你需要的是在性能会话缓存。本地存储只适用于离线应用程序。

,你可以看看这个 - http://turbomanage.wordpress.com/2010/07/12/caching-batching-dispatcher-for-gwt-dispatch/

+0

正如我在问题中提到的,我*不*探索gwt-dispatch。 – Swapnil 2012-07-30 18:04:23

+0

即使没有gwt-dispatch,你也可以很好地将该方法应用于你的代码。在这种情况下,使用HashMap将searchCriteria对象存储为key,将ListData对象存储为值。这种方法非常通用,并且可以很好地缓存各种类型的数据请求与结果。您可以选择使用您自己的Cacheable vs. Result接口来创建通用系统。 – Gautam 2012-07-30 18:44:35

+0

是的,但这个问题不是关于如何设计/实现缓存。这更多关于阿德里安。 B回答。不管怎么说,还是要谢谢你。 – Swapnil 2012-08-02 04:55:17