How can we store data in the application area for caching purposes?

I store data in the application area. I want to clear this data every hour. Infact uses it as a one hour cache. What is the best way to implement this? We used to use a session area to store this data, and it was used to expire after the session expires. Since this data is unique in the application, we want to save it in the application area.

+4
source share
4 answers

We found a way to clear application area variables using ServletContextListener and Timer.

public class SampleListener implements ServletContextListener { public static final long _startTimerDelayMin = 10; // In minutes public static final long _startTimerPeriodMin = 60; // In minutes Timer timer; ServletContext context =null; public void contextInitialized(ServletContextEvent contextEvent) { context = contextEvent.getServletContext(); scheduleTimer(); } public void scheduleTimer() { long delay = _startTimerDelayMin * 60000; //initial delay set to _startTimerDelayMin minutes as per msecs long period = _startTimerPeriodMin * 60000; //subsequent rate set to _startTimerPeriodMin minutes as per msecs timer = new Timer(); timer.scheduleAtFixedRate(new RemindTask(), delay, period); } public void contextDestroyed(ServletContextEvent arg0) { //Stopping Timer Thread once context destroyed timer.cancel(); } private static String getPropertyValue(String key){ String value = ""; try{ value = Util.getPropertyValueOfKey(key).trim(); }catch(IOException e){ } return value; } /** * This class is invoked at given interval to clear the application scope variable for browse call which have not been used for given time * */ class RemindTask extends TimerTask { public void run() { clearScopeVariables(); } /** * This function has logic to clear the application scope variable for browse call which have not been used for given time */ public void clearScopeVariables() { Date dt = new Date(); Enumeration<String> applicationScopeVarNames = (Enumeration<String>)context.getAttributeNames(); // TODO: clear the scope variables } } 

Add listener in web.xml

0
source

For a very simple cache, you can use Google gua MapMaker : Here is an example taken from javadoc:

  ConcurrentMap<Key, Graph> graphs = new MapMaker() .concurrencyLevel(4) .softKeys() .weakValues() .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .makeComputingMap( new Function<Key, Graph>() { public Graph apply(Key key) { return createExpensiveGraph(key); } }); 

There are two methods, expireAfterWrite and expireAfterRead , to do what yuo needs. And for free, you have a stream-safe map with weak values, soft keys, and a lazy rating if you want / need it :)

+5
source

Depending on whether you want to aggressively clean up expired data (to restore memory) or just want to re-install after expiration, the approach will be completely different.

If you just want to double-check, I would distribute SoftReference, for example:

 public class ExpiringSoftReference<T> extends SoftReference<T> implements Serializable { private final long _expirationMoment; public ExpiringSoftReference(Object referent, long duration, TimeUnit unit) { this(referent, System.currentTimeMillis() + unit.toMillis(duration); } private ExpiringSoftReference(Object referent, long expirationMoment) { super(referent); _expirationMoment = expirationMoment; } public T get() { if (System.currentTimeMillis() >= _expirationMoment) { clear(); } return super.get(); } private Object writeReplace() throws ObjectStreamException { return new SerializedForm<T>(get(), _expirationMoment); } private static class SerializedForm<T> implements Serializable { private final T _referent; private final T _expirationMoment; SerializedForm(T referent, long expirationMoment) { _referent = referent; _expirationMoment = expirationMoment; } private Object readResolve() throws ObjectStreamException { return new ExpiringSoftReference<T>(_referent, _expirationMoment); } } } 

If you want to aggressively restore memory, you need to implement some sort of garbage collection. The approach should be to first put all links in the thread safety priority queue, and then look at the first element to see if at least one of the links has expired:

 public class ExpiringSoftReference<T> extends SoftReference<T> implements Comparable<ExpiringSoftReference>, Serializable { // same as above, plus public int compareTo(ExpiringSoftReference other) { if (this._expirationMoment < other._expirationMoment) { return -1; } else if (this._expirationMoment > other._expirationMoment) { return 1; } else { return 0; } } final long expiration() { return _expirationMoment; } } public class ExpirationEnforcer { private final PriorityBlockingQueue<ExpiringSoftReference> _byExpiration = new ...(); public void add(ExpiringSoftReference reference) { _byExpiration.put(reference); } public synchronized void tick() { long now = System.currentTimeMillis(); while (true) { ExpiringSoftReference candidate = _byExpiration.peek(); if (candidate == null || candidate.expiration() > now) { return; } ExpirationSoftReference toClear = _byExpiration.peek(); toClear.clear(); } } } 

You will need to call tick () in the queue every couple of seconds or something else. For this, in Java EE you will need to use a timer service or something like that.

+1
source

Where does this data come from? If from a database, you should use ORM with support for first and second level caches, such as Hibernate / JPA. Thus, you do not need to change your code so that it depends on the cache (which would make it rather difficult to maintain / reusable). You simply run SQL queries in the usual way, and Hibernate / JPA will return objects from the Java cache if necessary.

See also:

0
source

Source: https://habr.com/ru/post/1346866/


All Articles