ЗАГРУЗИТЬ и КЕШИТЬ данные в области приложения с помощью @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());
    }        
}

Можете ли вы увидеть большие проблемы, концептуальные ошибки или что-то в этом примере?

Мои основные проблемы были

  1. Если бы оба были @Singleton (ммм), я мог бы добавить @DependsOn("Rooms") на компоненте Cacher, чтобы обеспечить загрузку Rooms перед использованием, но с @Singleton а также @Stateless Я не могу... будет @Stateless bean-компонент всегда загружается до того, как CDI внедрит его в @Singleton?

  2. @Singleton призвание @Stateless кажется странным (я видел примеры обратного); я должен изменить дизайн, поставив @Singleton экземпляр внутри @Stateless EJB?

  3. Правильно ли загружать и кэшировать в @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.

Работает отлично.

Другие вопросы по тегам