LOAD and CACHE data scoped with @Singleton and @Stateless

I'm looking for elegant solutions to the old problem of loading and caching static shared data at application startup (with infinite lifecycle).

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

I have @Entity

and the @Stateless

EJB lo is loading an object from the database. My thought was to add an @Singleton

EJB for data caching; I also decided to keep the original EJB separate so as not to break the SRP (and because it might be used by other actors to bypass the cache in the future).

Please take a look at this simplified proof of concept :

An object

@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, concept errors, or something in this example?

My main problems were

  • If both were @Singleton

    (mehh), I could add @DependsOn("Rooms")

    a Bean to the cacher to ensure that Rooms are already loaded before use, but with @Singleton

    and @Stateless

    I cannot ... will the @Stateless

    bean always load before CDI injects it @Singleton

    ?

  • @Singleton

    the call @Stateless

    seems strange (I've seen examples of the opposite); should I change the design by putting an instance @Singleton

    inside an @Stateless

    EJB?

  • Is it correct to load and cache the method @PostConstruct

    ?

+2


source to share


1 answer


Ok I did some tests and I tried it as well @Decorator

. This still seems to be the best.

The @Entity bean and @Stateless bean are the same as the question, while I modified the @Singleton bean as follows, adding the classic time cache as well:

@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 @PostConstruct or @EJB needed, no problems syncing with the base, @ inject-ed @Stateless bean.

It works great.

0


source







All Articles