First, let's understand our bean declaration:
@Singleton
@Startup
public class UserCacheBean {
...
@PostConstruct
protected void init() {
cache = new ConcurrentLinkedQueue<>();
loadCache();
}
}
We are using a Singleton because it has one and only one instance in the application context. This is the way we want a data cache to be – we don't want different data being shared.
Also, note that we used the @Startup annotation. This tells the server that this bean should be executed once it is loaded and that the method annotated with @PostConstruct is used for it.
So, we use the startup time to load our cache:
protected void loadCache() {
List<User> list = em.createQuery("SELECT u FROM USER
as u").getResultList();
list.forEach((user) -> {
cache.add(user);
});
}
Now, let's check the object holding our cache:
protected Queue<User> cache = null;
...
cache = new ConcurrentLinkedQueue<>();
ConcurrentLinkedQueue is a list that's built with one main purpose – to be accessed by multiple processes in a thread-safe environment. That's exactly what we need. This also offers great performance when we need to access its members.
Finally, let's check the access to our data cache:
Lock(LockType.READ)
public List<User> get() {
return cache.stream().collect(Collectors.toList());
}
We annotated the get() method with LockType.READ, which is telling the concurrency manager that it can be accessed by multiple processes at once in a thread-safe way.