从名字上来看JBoss Cache很容易使人联想到JBoss Web服务器,但是实际上,你可以“认为”他们之间没有任何关系,学习使用JBoss Cache时不需要你对JBoss Web服务器有任何了解。
什么是JBoss Cache
就像它的名字所显示的那样,它是一种缓存。它被设计用来缓存那些经常被访问的Java对象,这样就可以明显的提高系统的性能,可以很轻松的解决掉数据访问的瓶颈,比如连接数据库等。
JBoss Cache是一种复制缓存,它可以自动与集群中的其他服务器同步状态,这样就可以保证在其中一台或者几台服务器突然挂掉之后恢复缓存,具有很高的可靠性能。
JBoss Cache存储结构为树状结构,使用Fqn(Full Qualified Name)唯一定位其中一个Node,如下图,其中每个方框代表一个独立的JVM。
以上只简单的介绍JBoss Cache的概念,详细信息请参考官方文档: http://jboss.org/jbosscache
既然cache是存在内存中的,那就需要应对各种突发性的事件,以保证它的高可靠性,比如内存不足,或者服务器宕机等,为了解决此类问题,JBoss Cache引入了CacheLoader的概念去备份内存中的缓存数据,同时为了提高系统的性能,CacheLoader可以被配置用来在系统启动的时候预加载部分或者全部历史缓存。
JBoss Cache附带了多种CacheLoader的默认实现,包括FileCacheLoader, JDBCCacheLoader, S3CacheLoader, TCPDelegatingCacheLoader, TransformingCacheLoader等,从名字可以很容理解每种CacheLoader的应用场景,本文将主要演示FileCacheLoader。
简单概括一下什么是CacheLoader
JBoss Cache可以通过CacheLoader将内存中的缓存备份到datastore中。如果JBoss Cache配置了CacheLoader,那么JBoss Cache将提供以下功能:
1. 当访问某个缓存元素的时候, 如果该元素不在内存中,比如它可能被钝化或者因为服务器重启了,那么CacheLoader就会自动的在datastore中查询该元素,如果存在,将会加载到内存中。
2. 当某个缓存元素被修改,添加或者删除的时候,CacheLoader会将这种变化持久化到datastore中。如果使用了事务,那会以事务为单位持久化这种变化。
好了,闲话不在多说了,详情可以参考官方的用户手册:http://docs.jboss.org/jbosscache/3.2.1.GA/userguide_en/html_single/index.html#d0e2507
下面将演示一下如果设置使用FileCacheLoader
首先创建一个FileCache类封装JBoss Cache的相关操作,如下:
package com.javaeye.terrencexu.jbosscache;
import java.io.File;
import java.util.Map;
import org.jboss.cache.Cache;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.loader.FileCacheLoader;
import org.jboss.cache.loader.FileCacheLoaderConfig;
/**
* <p>
* This is demo to illustrate how to use the JBoss Cache to cache your
* frequently accessed Java objects in order to dramatically improve
* the performance of your applications. This makes it easy to remove
* data access bottlenecks, such as connecting to a database.
* </p>
* <p>
* As a rule of thumb, it is recommended that the FileCacheLoader not
* be used in a highly concurrent, transactional or stressful environment,
* ant its use is restricted to testing.
* </p>
*
* @author TerrenceX
*
* @param <T>
*/
public class FileCache<T> {
/**
* The JBoss Cache, used to cache frequently accessed Java objects.
*/
private Cache<String, T> cache;
/**
* @constructor
* @param fsCacheLoaderLocation The file system location to store the cache
*/
public FileCache(File fsCacheLoaderLocation) {
cache = initCache(fsCacheLoaderLocation);
}
/**
* Create a Cache and whose cache loader type is File Cache Loader
*
* @param fsCacheLoaderLocation The file position used to store the cache.
*
* @return Cache
*/
public Cache<String, T> initCache(File fsCacheLoaderLocation) {
// initiate a FileCacheLoader instance
FileCacheLoader fsCacheLoader = new FileCacheLoader();
// prepare the file cache loader configuration file for File Cache Loader
FileCacheLoaderConfig fsCacheLoaderConfig = new FileCacheLoaderConfig();
fsCacheLoaderConfig.setLocation(fsCacheLoaderLocation.toString());
fsCacheLoaderConfig.setCacheLoader(fsCacheLoader);
// set configuration to File Cache Loader
fsCacheLoader.setConfig(fsCacheLoaderConfig);
// prepare the configuration for Cache
Configuration config = new Configuration();
config.setCacheLoaderConfig(new CacheLoaderConfig());
config.getCacheLoaderConfig().addIndividualCacheLoaderConfig(fsCacheLoaderConfig);
// create a Cache through the default cache factory
return new DefaultCacheFactory<String, T>().createCache(config);
}
/**
* Add a new node into the tree-node hierarchy
*
* @param fqn Full Qualified Name for the new node
* @return
*/
public Node<String, T> addNode(Fqn<String> fqn) {
return cache.getRoot().addChild(fqn);
}
/**
* Remove a specified node from the tree-node hierarchy
*
* @param fqn Full Qualified Name for the specified node
*/
public void removeNode(Fqn<String> fqn) {
cache.removeNode(fqn);
}
/**
* Add node information to the specified node.
*
* @param fqn Full Qualified Name for the specified node
* @param key The key of the node information
* @param value The value of the node information
*/
public void addNodeInfo(Fqn<String> fqn, String key, T value) {
cache.put(fqn, key, value);
}
/**
* Batch add node information to the specified node.
*
* @param fqn Full Qualified Name for the specified node
* @param infos Node informations map
*/
public void addNodeInfos(Fqn<String> fqn, Map<String, T> infos) {
cache.put(fqn, infos);
}
/**
* Get node information from the specified node.
*
* @param fqn Full Qualified Name for the specified node
* @param key The key of the node information
* @return
*/
public T getNodeInfo(Fqn<String> fqn, String key) {
return cache.get(fqn, key);
}
/**
* Remove node information from the specified node.
*
* @param fqn Full Qualified Name for the specified node
* @param key The key of the node information
*/
public void removeNodeInfo(Fqn<String> fqn, String key) {
cache.remove(fqn, key);
}
}
下面是一个测试的例子:
package com.javaeye.terrencexu.jbosscache;
import java.io.File;
import org.jboss.cache.Fqn;
public class Main {
public static void main(String[] args) {
FileCache<String> fileCache = new FileCache<String>(new File("d:\\tmp"));
Fqn<String> jimmyFqn = Fqn.fromString("/com/manager/jimmy");
Fqn<String> hansonFqn = Fqn.fromString("/com/developer/hanson");
fileCache.addNode(jimmyFqn);
fileCache.addNode(hansonFqn);
fileCache.addNodeInfo(jimmyFqn, "en-name", "Jimmy Zhang");
fileCache.addNodeInfo(jimmyFqn, "zh-name", "Zhang Ji");
fileCache.addNodeInfo(hansonFqn, "en-name", "Hanson Yang");
fileCache.addNodeInfo(hansonFqn, "zh-name", "Yang Kuo");
String enName = fileCache.getNodeInfo(hansonFqn, "en-name");
System.out.println(enName);
}
}
运行结果如下:
- JBossCache MBeans were successfully registered to the platform mbean server.
- JBoss Cache version: JBossCache 'Malagueta' 3.2.5.GA
Hanson Yang
生成的缓存文件目录结构如下:
D:/tmp/com.fdb/manage.fdb/jimmy.fdb/data.dat
D:/tmp/com.fdb/developer.fdb/hanson.fdb/data.dat
本文仅仅是通过FileCacheLoader演示如何使用JBoss Cache,在真正的集群环境中建议不要使用FileCacheLoader, 它只是用来测试玩玩儿而已。
-- done --