使用@Singleton和@Stateless加载和CACHE应用程序作用域数据

时间:2014-11-04 10:44:30

标签: java java-ee jpa singleton ejb

我正在寻找一个优雅的解决方案来解决在应用程序启动时(具有无限生命周期)加载和缓存静态共享数据的旧问题。

我的老方法是Spring Singleton Bean,但我现在正尝试用 JAVA EE 6 (JPA2,EJB3.1,CDI)来实现它。

我有@Entity,而@Stateless EJB从数据库加载实体。我的想法是添加一个@Singleton EJB来缓存数据;我还决定将原始EJB保持分离,以防止违反SRP(并且因为将来可能会被其他参与者绕过缓存使用)。

请看一下这个简化的 概念验证

实体

@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();
    }
}

cacher的

@Singleton
public class RoomsCached {

    @EJB
    Rooms rooms;

    private List<Room> cachedRooms; // GETTER

    @PostConstruct
    public void initCache(){
        this.cachedRooms = Collections.unmodifiableList(rooms.findAll());
    }        
}

你能看到这个例子中的大问题,概念错误或什么吗?

我主要担心的是

  1. 如果两者都是@Singleton(mehh),我可以在cacher bean上添加@DependsOn("Rooms"),以确保在使用之前已经加载了Rooms,但使用@Singleton@Stateless我无法在CDI将@Stateless注入@Singleton之前将@Singleton bean加载?

  2. @Stateless调用@Singleton似乎很奇怪(我见过相反的例子);我应该通过将@Stateless实例放在@PostConstruct EJB中来改变设计吗?

  3. 在{{1}}方法中加载和缓存是否正确?

1 个答案:

答案 0 :(得分:1)

好吧,我做了一些测试,我也尝试了@Decorator方式。这似乎仍然是最好的。

@Entity bean和@Stateless bean是同一个问题,而我更改了@Singleton bean如下,还添加了经典的定时缓存:

@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的同步问题。

它运作良好。