java - 使用@Singleton 和@Stateless 加载和缓存应用程序范围的数据

标签 java jakarta-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();
    }
}

缓存器

@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),我可以在缓存 bean 上添加 @DependsOn("Rooms"),以确保 Rooms 已经在使用之前加载,但是使用 @Singleton@Stateless 我不能...将 @Stateless bean 总是在 CDI 注入(inject)之前加载它变成了 @Singleton ?

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

  3. @PostConstruct方法中加载缓存是否正确?

最佳答案

嗯,我做了一些测试,我也尝试了@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 没有同步问题。

效果很好。

关于java - 使用@Singleton 和@Stateless 加载和缓存应用程序范围的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26733141/

相关文章:

java - 在并行流式处理之前或期间有效地预处理 CSV 数据

java - 在一个 JBoss 上无法从 java.lang.String 类型转换为 java.util.Date 类型,但在另一个 JBoss 上则正常

java - 排除 ScheduleExpression 中的日期

mysql - 未设置将 MySQL 数据库连接到 Glassfish 类路径或类名错误

java - 如何使用EclipseLink为公共(public)接口(interface)下的独立实体声明接口(interface)描述符?

java - 延迟初始化异常 : load lazy attribute from a session different from the original one in Hibernate

java - 制作小程序

java - 用于修复格式错误的 URI 的 Scala 或 Java 库

java - 如何以编程方式找出一个字符串可以容纳多少个 "tabs"?

java - 在数据库中读取/写入 POJO 作为 JSON 字符串