本处介绍JBossCache相关的主要API,我们目的通过本部分描述,读者可以使用JBossCache API,在自己的应用中使用JBossCache。
Cache 接口是和JBossCache交互的主要机制。它是用 CacheFactory 构建并可选择地启动的。CacheFactory 允许你从 Configuration 对象或 XML 文件创建 Cache。缓存将数据组织到由节点组成的树型结构里。一旦你具有了到 Cache 的引用,你可以用它来在树型结构里查找 Node 对象,并存储数据。
请注意,上面的图表只是描述了一些流行的 API 方法。阅读上述接口的 Javadoc 是学习 API 的最甲途径。
Cache接口的实例只能通过 CacheFactory 创建。这和 JBoss Cache 1.x 不同,旧的 TreeCache 可以直接初始化。CacheFactory 提供了用于创建 Cache 的大量重载方法,但它们基本上都是做的同一件事情:
CacheFactory factory = new DefaultCacheFactory(); Cache cache = factory.createCache();
CacheFactory factory = new DefaultCacheFactory(); Cache cache = factory.createCache("cache-configuration.xml");
CacheFactory factory = new DefaultCacheFactory(); Cache cache = factory.createCache("/opt/configurations/cache-configuration.xml",false); Configuration config = cache.getConfiguration(); config.setClusterName(this.getClusterName()); // Have to create and start cache before using it cache.create(); cache.start();
如上面我们初始化和启动了缓存,接下来让我们使用 Cache API 来访问缓存里的 Node 然后对这个节点做一些简单的读和写,如下代码段:
28 Cache cache = createCacheUseDefault(); 29 Node rootNode = cache.getRoot(); 30 Fqn helloWorldFqn = Fqn.fromString("/root/helloWorld"); 31 Node helloWorld = rootNode.addChild(helloWorldFqn); 32 helloWorld.put("isJBossCache", Boolean.TRUE); 33 helloWorld.put("content", new Content("HelloWorld")); 35 System.out.println(helloWorld.get("isJBossCache")); 36 System.out.println(helloWorld.get("content")); 37 System.out.println(helloWorld.getFqn()); 38 System.out.println(helloWorld.getKeys()); 40 helloWorld.remove("isJBossCache"); 41 helloWorld.remove("content"); 43 System.out.println(helloWorld.get("isJBossCache")); 44 System.out.println(helloWorld.get("content")); 46 rootNode.removeChild(helloWorldFqn);
如上 28-29 行创建默认 Cach 后获取一个跟节点;30 行JBoss Cache 用树状的结构存储数据,树状结构包含多个节点,所有节点都用 Fqn 来识别; 31-33 行创建一个新节点,并向该节点存储数据; 35-38 行测试读取存储的数据; 40-41 行移除添加的数据; 46 行将新创建的节点从跟节点移除。
为了便于使用, Cache 接口也开放以 “Fqn 类” 作为参数执行 put/get/remove 操作:Cache cache = createCacheUseDefault(); Node rootNode = cache.getRoot(); Fqn helloWorldFqn = Fqn.fromString("/root/helloWorld"); Node helloWorld = rootNode.addChild(helloWorldFqn); cache.put(helloWorldFqn, "isJBossCache", Boolean.TRUE); cache.put(helloWorldFqn, "content", new Content("HelloWorld")); System.out.println(helloWorld.get("isJBossCache")); System.out.println(helloWorld.get("content")); System.out.println(cache.getRoot().hasChild(helloWorldFqn)); cache.removeNode(helloWorldFqn);
节点应该被看作一个命名逻辑数据组。节点应该用来包含单个数据记录里的数据, 例如,某个人或帐号的信息。它应该具有缓存的所有方面 - 锁、缓存加载、复制和逐出 - 对于每个节点设置。因此, 存储在单个节点里任何分组信息都将被当作单个的原子单元。
前面的部分在其示例里使用了 Fqn 类;现在让我们对其进行进一步的了解。Fully Qualified Name (Fqn) 封装了代表对应缓存树型机构里某个位置的路径的名称列表。该列表里的元素通常是 String 但也可以是任何 Object 或混合类型。 Fqn 代表一个到特定节点的路径或 Cache 中的路径。
这个路径可以是绝对的(也就是相对于根节点),也可以相对于缓存里的任何节点。关于使用 Fqn 的 API 调用的文档里会告诉你该 API 是否使用相对还是绝对的 Fqn。Fqn 提供了大量的工厂方法,详情请参考JBossCache Javadoc。下面的例子解释了创建 FQN 最常用的途径:15 Fqn strFqn = Fqn.fromString("/people/Smith/Joe/"); 16 Fqn eleDqn = Fqn.fromElements("accounts", "NY", new Integer(12345));
如上15 行我们创建一个 Fqn 指向节点 Joe,节点 Joe 在父节点 Smith 下,而 节点Smith 位于节点 people 下,我们通过 String 字符串创建 Fqn;16 行我们用其他的数据类型来创建 Fqn。特别注意,Fqn.fromElements("a", "b","c") 与Fqn.fromString("/a/b/c") 的等效的,它们都是创建了一个指向节点 c 的Fqn。
使用完毕后停止并销毁缓存是通常的做法,特别是在集群应用中缓存使用大量 JGroups 通道的情况下,停止并销毁缓存确保了能够正确地清理网络套接字和维护线程等资源。我们可以通过缓存提供的方法停止和销毁缓存,如下所示:
cache.stop(); cache.destroy();
注意,已调用 stop() 的缓存可以用 start() 重启启动。类似地,已调用 destroy() 的缓存也可以用 create() 重新创建,并可调用 start()重启启动缓存。
虽然严格来说,缓存模式并非 API 的一部分,但缓存所操作的模式可影响到任何 put 或 remove 操作的行为,所以在这里我们将简单的描述出这些模式。JBoss Cache 模式是通过org.jboss.cache.config.Configuration.CacheMode 定义的,它是一个枚举类型,包括的缓存模式如下:
JBoss Cache 提供一个方便的机制以注册缓存事件的通知:
Object myListener = new MyCacheListener(); cache.addCacheListener(myListener);
14 @CacheListener 15 public class MyListener { 17 @CacheStarted 18 @CacheStopped 19 public void cacheStartStopEvent(Event e) { 20 switch (e.getType()) { 21 case CACHE_STARTED: 22 System.out.println("Cache has started"); 23 break; 24 case CACHE_STOPPED: 25 System.out.println("Cache has stopped"); 26 break; 27 } 28 } 30 @NodeCreated 31 @NodeRemoved 32 @NodeVisited 33 @NodeModified 34 @NodeMoved 35 public void logNodeEvent(NodeEvent e) { 36 System.out.println(e.getType() + " on node " + e.getFqn() + " has occured"); 37 }
13 CacheFactory factory = new DefaultCacheFactory(); 14 Cache cache = factory.createCache(false); 15 MyListener myListener = new MyListener(); 16 cache.addCacheListener(myListener); 17 cache.start(); 19 Node root = cache.getRoot(); 20 Fqn abcFqn = Fqn.fromString("/a/b/c"); 21 Node abc = root.addChild(abcFqn); 22 abc.put("content", new Content("abc test")); 23 abc.get("content"); 24 cache.removeNode(abcFqn); 25 cache.stop(); 26 cache.destroy();
Cache has started NODE_CREATED on node /a has occured NODE_CREATED on node /a has occured NODE_CREATED on node /a/b has occured NODE_CREATED on node /a/b has occured NODE_CREATED on node /a/b/c has occured NODE_CREATED on node /a/b/c has occured NODE_MODIFIED on node /a/b/c has occured NODE_MODIFIED on node /a/b/c has occured NODE_MODIFIED on node /a/b/c has occured NODE_MODIFIED on node /a/b/c has occured NODE_VISITED on node /a/b/c has occured NODE_VISITED on node /a/b/c has occured NODE_REMOVED on node /a/b/c has occured NODE_REMOVED on node /a/b/c has occured Cache has stopped
在缺省情况下,所有的通知都是同步的,因此它们在产生事件的调用者线程里发生。确保缓存 listener 实现不会占用需长时间运行的任务中的线程是一个好的办法。或者,你可以设置 CacheListener.sync 属性为 false,此时你不会在调用者线程里得到通知。
缓存加载器是 JBoss Cache 的重要组成部分。它们允许节点持久化到磁盘或远程缓存到群集里,而且允许在缓存用尽内存时进行钝化。此外,缓存加载器允许 JBossCache 执行 “warm starts”,此时的内存状态可以从持久性存储中预加载。JBossCache 附带了大量的缓存加载器的实现。如下列出JBossCache提供的缓存加载器:
逐出策略是缓存加载器的对应物。要确保缓存在填充时不会用尽内存,使用逐出策略是必要的。在独立线程里运行的逐出算法逐出内存状态并释放内存。如果配有缓存加载器,在需要时状态可以从缓存加载器里获得。逐出策略可对每个区进行配置,所以缓存里不同的子树可以有不同的逐出首选项。JBossCache 附带几个注册策略: