我已经实现了一种缓存豆缓存数据对象为EJB辛格尔顿。我不知道这是在EJB的正确方法:
@Singleton
public class MyCache {
int DEFAULT_CACHE_SIZE = 30;
int DEFAULT_EXPIRES_TIME = 60000;
long expiresTime = 0;
long lastReset = 0;
Cache cache = null;
....
@PostConstruct
void init() {
resetCache();
}
public void resetCache() {
cache = new Cache(DEFAULT_CACHE_SIZE);
lastReset = System.currentTimeMillis();
}
public void put(String key, Object value) {
cache.put(key, value);
}
public Object get(String key) {
// test if cache is expired
if (expiresTime > 0) {
Long now = System.currentTimeMillis();
if ((now - lastReset) > expiresTime) {
logger.finest("...... Cache expired!");
resetCache();
}
}
return cache.get(key);
}
class Cache extends LinkedHashMap<String, Object> implements Serializable {
private static final long serialVersionUID = 1L;
private final int capacity;
public Cache(int capacity) {
super(capacity + 1, 1.1f, true);
this.capacity = capacity;
}
protected boolean removeEldestEntry(Entry<String, Object> eldest) {
return size() > capacity;
}
}
}
我的问题是:这是执行程序范围的缓存机制的正确方法?
我有一个缓存的内容被意外地改变了印象。会发生这种事?例如,如果EJB被钝化?我在Payara41服务器上运行。
或者我必须使用:
cache = Collections.synchronizedMap(new Cache(DEFAULT_CACHE_SIZE));
代替:
cache = new Cache(DEFAULT_CACHE_SIZE);
首先,不为bean指定的并发性管理,它下降到默认的“容器”。
从EJB 3.1规范:
当设计一个Singleton会话bean,开发者必须确定Bean将使用容器是否管理或豆管理的并发。通常,辛格尔顿豆将被指定为具有容器管理的并发划分。这是如果没有指定并发管理类型的默认。
然后,容器并发管理需要锁定型的方法级规格。只要那些是没有的,默认的“写”适用于:
默认情况下,如果不是一个Singleton豆与容器管理的并发划界的方法中指定的并发性锁定属性注释,该方法的并发锁定属性的值被定义为写入。
访问您的bean的方法的上述手段必须是同步的,甚至可能超过你的实际需要。您可以设置“读取”锁定类型只读方法(GET),以允许并发读取访问。
和容器管理锁的解决方案有一个缺点,考虑是否有写锁放置操作就意味着整个“高速缓存”被阻断,因此获取或发布是可以并行,无论关键是不同的。如果你的缓存实现是一个并行地图,你可以使用它没有锁定。
如果您有缓存更多的要求,我会用的Infinispan它们提供了更好的性能。这里的高速缓存可以是本地或分布在集群。
阅读本blog from Adam Bien后,我现在提高了我下面的方式代码:
例:
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN) // added concurrency management
public class MyCache {
int DEFAULT_CACHE_SIZE = 30;
int DEFAULT_EXPIRES_TIME = 60000;
long expiresTime = 0;
long lastReset = 0;
Cache cache = null;
....
@PostConstruct
void init() {
resetCache();
}
public void resetCache() {
cache = new Cache(DEFAULT_CACHE_SIZE);
lastReset = System.currentTimeMillis();
}
public void put(String key, Object value) {
cache.put(key, value);
}
public Object get(String key) {
// test if cache is expired
if (expiresTime > 0) {
Long now = System.currentTimeMillis();
if ((now - lastReset) > expiresTime) {
logger.finest("...... Cache expired!");
resetCache();
}
}
return cache.get(key);
}
// changed from LinkedHashMap to ConcurrentHashMap
class Cache extends ConcurrentHashMap<String, Object> implements Serializable {
private static final long serialVersionUID = 1L;
private final int capacity;
public Cache(int capacity) {
super(capacity + 1, 1.1f);
this.capacity = capacity;
}
protected boolean removeEldestEntry(Entry<String, Object> eldest) {
return size() > capacity;
}
}
}
我觉得这是现在更正确实施。