ЗАГРУЗИТЬ и КЕШИТЬ данные в области приложения с помощью @Singleton и @Stateless
Я ищу элегантные решения старой проблемы загрузки и кэширования статических, общих данных при запуске приложения (с бесконечным временем жизни).
Мой старый способ был 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());
}
}
Можете ли вы увидеть большие проблемы, концептуальные ошибки или что-то в этом примере?
Мои основные проблемы были
Если бы оба были
@Singleton
(ммм), я мог бы добавить@DependsOn("Rooms")
на компоненте Cacher, чтобы обеспечить загрузку Rooms перед использованием, но с@Singleton
а также@Stateless
Я не могу... будет@Stateless
bean-компонент всегда загружается до того, как CDI внедрит его в@Singleton
?@Singleton
призвание@Stateless
кажется странным (я видел примеры обратного); я должен изменить дизайн, поставив@Singleton
экземпляр внутри@Stateless
EJB?Правильно ли загружать и кэшировать в
@PostConstruct
метод?
1 ответ
Ну, я сделал несколько тестов, и я также попробовал @Decorator
путь. Это все еще кажется лучшим.
Бин @Entity и бин @Stateless - это одно и то же, в то время как я изменил бин @Singleton следующим образом, также добавив классический таймерный кэш:
@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.
Работает отлично.