使用@Singleton 和@Stateless 加载和缓存应用程序范围的数据 [英] LOAD and CACHE application-scoped data with @Singleton and @Stateless
问题描述
我正在寻找一种优雅的解决方案来解决在应用程序启动时加载和缓存静态、共享数据(具有无限生命周期)的老问题.
I'm looking for an elegant solutions to the old problem of loading and caching static, shared data at application startup (with an infinite lifetime).
我的旧方法是使用 Spring Singleton Bean,但我现在正在尝试使用 JAVA EE 6(JPA2、EJB3.1、CDI)来实现它.
My old way was a Spring Singleton Bean, but I'm trying now to achieve it with JAVA EE 6 (JPA2, EJB3.1, CDI).
我有一个 @Entity
和一个 @Stateless
EJB,用于从数据库加载实体.我的想法是添加一个 @Singleton
EJB 来缓存数据;我还决定将原始 EJB 分开,以防止违反 SRP(因为将来它可能会被其他参与者绕过缓存使用).
I have an @Entity
, and an @Stateless
EJB lo load the entity from database. My thought was to add a @Singleton
EJB to cache the data; I also decided to keep the original EJB separated, to prevent violating SRP (and because in the future it might be used bypassing the cache, by other actors).
请看一下这个简化的概念证明:
Please take a look at this simplified Proof Of Concept:
实体
@NamedQuery(name="Room.findAll", query="SELECT r FROM Room r")
@Entity
public class Room {
@Id
private Integer id; // GETTER, SETTER
private String description; // GETTER, SETTER
}
加载器
@Stateless
public class Rooms {
@PersistenceContext
EntityManager em;
public List<Room> findAll() {
return em.createNamedQuery("Room.findAll",Room.class).getResultList();
}
}
缓存
@Singleton
public class RoomsCached {
@EJB
Rooms rooms;
private List<Room> cachedRooms; // GETTER
@PostConstruct
public void initCache(){
this.cachedRooms = Collections.unmodifiableList(rooms.findAll());
}
}
你能在这个例子中看到大问题、概念错误或其他东西吗?
Can you see big problems, conceptual errors or something in this example ?
我主要关心的是
如果两者都是
@Singleton
(mehh),我可以在缓存 bean 上添加@DependsOn("Rooms")
,以确保 Rooms 已经在使用之前加载,但是使用@Singleton
和@Stateless
我不能......在 CDI 注入之前总是加载@Stateless
bean它变成@Singleton
?
If both were
@Singleton
(mehh), I could have added@DependsOn("Rooms")
on the cacher bean, to ensure Rooms is already loaded before being used, but with@Singleton
and@Stateless
I can't... will@Stateless
bean always be loaded before CDI injects it into@Singleton
?
@Singleton
调用 @Stateless
看起来很奇怪(我见过相反的例子);我应该通过将 @Singleton
实例放在 @Stateless
EJB 中来更改设计吗?
@Singleton
calling @Stateless
seems weird (I've seen examples of the opposite); should I change design by putting the @Singleton
instance inside the @Stateless
EJB ?
在@PostConstruct
方法中加载和缓存是否正确?
Is it right to load and cache in the @PostConstruct
method ?
推荐答案
嗯,我已经做了一些测试,我也尝试了 @Decorator
的方式.这似乎仍然是最好的.
Well, I've made some tests, and I've also tried the @Decorator
way. This still seems to be the best one.
@Entity bean 和@Stateless bean 是相同的问题,而我将@Singleton bean 更改如下,还添加了经典的定时缓存:
@Entity bean and @Stateless bean are the same of the question, while I've changed the @Singleton bean as follows, also adding the classic timed cache:
@Singleton
public class RoomsCached {
@Inject
Rooms rooms;
private List<Room> cachedRooms;
private long timeout = 86400000L; // reload once a day
private long lastUpdate;
public List<Room> getCachedRooms() {
initCache();
return cachedRooms;
}
public void initCache() {
if (cachedRooms == null || expired()) {
cachedRooms = Collections.unmodifiableList(rooms.findAll());
lastUpdate = System.currentTimeMillis();
}
}
private boolean expired() {
return System.currentTimeMillis() > lastUpdate + timeout;
}
}
不需要@PostConstruct,也不需要@EJB,与底层@inject-ed @Stateless bean 没有同步问题.
No need to @PostConstruct, nor to @EJB, no sync issues with the underlying, @inject-ed @Stateless bean.
效果很好.
这篇关于使用@Singleton 和@Stateless 加载和缓存应用程序范围的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!