Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
689 views
in Technique[技术] by (71.8m points)

java - 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).

My old way was a Spring Singleton Bean, but I'm trying now to achieve it with JAVA EE 6 (JPA2, EJB3.1, CDI).

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:

Entity

@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
}

Loader

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

Can you see big problems, conceptual errors or something in this example ?

My main concerns were

  1. 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 ?

  2. @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 ?

  3. Is it right to load and cache in the @PostConstruct method ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Well, I've made some tests, and I've also tried the @Decorator way. This still seems to be the best one.

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

}

No need to @PostConstruct, nor to @EJB, no sync issues with the underlying, @inject-ed @Stateless bean.

It's working great.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...