objetos

Implementing a simple object cache with Ehcache

Recently I have been reviewing the technical architecture of a Java EE project that was having serious scalability problems. In Development everything was going like a shot, but with a significant but not outrageous number of records (just 100,000) we were encountering response times for some of the online operations that could take up to 5 minutes. Obviously these times are not acceptable for a web operation, so it was urgent to detect sources of problems and optimize processes.

Actually, there was no part of the code that was 100% at fault, but the implemented functionality, excessively flexible for the user, allowed the user to perform searches and operations that finally implied a succession of queries, filtering, union/intersection operations of huge lists, persistence…

For many of the lists that were handled, it was possible to guarantee their invariability over a long period of time. Data, for example, relating to provinces. Therefore, it seemed that implementing a cache of these lists, and especially of the final results after the aforementioned join/intersection operations, etc., could be appropriate. It is true that Hibernate allows result caching (and in fact uses Ehcache), but in this case we are talking about post-processed results, so it would not be enough.

Caching objects in a Java EE application is basically trivial: we always have the option to place the object in application context (ServletContext) and retrieve it whenever we want. However, this approach is still something “toy”. We decided to use Ehcache in the first place because we knew that Hibernate took good advantage of it, but above all because, with an extremely simple development, we obtain important functional advantages such as:

  • Content expiration management. After a certain time, the cache deletes the cached object and starts returning NULL to subsequent requests. It removes the responsibility of persisting the lifetime of a cached object.
  • Configuration of the maximum number of objects to cache in memory. You can set the number of objects to cache in memory. Ehcache takes care of serializing to disk everything that is left over, and retrieve it when necessary. It goes without saying that all objects to be cached must be serializable.
  • Possibility of cluster deployment.
  • Cache deletion during application server shutdown.
  • Don’t reinvent the wheel!

In the end we developed a simple Manager class, implementing the Singleton pattern, which interacts with Ehcache. And in certain areas of the application, invoke the cache to retrieve the objects that were previously generated online.

I’m going to put the code, because in the end, without a little help, this will come to nothing 🙂 However, I would like to emphasize that the process of 5 minutes at the end, with a little love, has become responsive in less than 10 seconds. A gain of 3000%…


/*

* File: CacheUtil.java

*

* Created on march 2009

*

*

* Copyright 2006-2029 Javier Echeverría Usúa (javieu at gmail.com)

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*     http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*

*/

package com.viavansi.framework.core.cache
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.viavansi.framework.core.persistencia.servicios.excepciones.ExcepcionServicio;
/**
* @author Javier Echeverria Usua (javieu at gmail.com)
* @author Felix Garcia Borrego (borrego at gmail.com)
* @author Alexis Castilla Armero (pencerval at gmail.com)
*/
public class CacheUtil {
public Object getCachedObject(String key) throws Exception{
if(minutosVidaDefault == 0)
minutosVidaDefault = MINUTOS_DEFAULT;
return getCachedObject(key, minutosVidaDefault);
}
public void putCachedObject(String key, Object info) throws Exception{
if(minutosVidaDefault == 0)
minutosVidaDefault = MINUTOS_DEFAULT;
putCachedObject(key, info, minutosVidaDefault);
}
public Object getCachedObject(String key, int minutosCache) throws Exception{
Cache cacheCustodia = getInstance(minutosCache);
Element element = cacheCustodia.get(key);
if(element != null){
return cacheCustodia.get(key).getValue();
}
else{
return null;
}
}
public void putCachedObject(String key, Object info, int minutosCache) throws Exception{
Cache cacheCustodia = getInstance(minutosCache);
cacheCustodia.put(new Element(key,info));
}
private Cache getInstance(int minutosCache) {
Cache cache = null;
//Todavía no existe
int timeTolife = minutosCache * 60;
CacheManager manager = CacheManager.getInstance();
String nombreCache = "viavansiCachedInfo" + minutosCache;
if (manager.cacheExists(nombreCache)) {
cache = manager.getCache(nombreCache);
} else {
// Configuramos el apagado en caso de Error de la JVM o parada inesperada.
System.setProperty("net.sf.ehcache.enableShutdownHook", "true");
manager.addCache(new Cache(nombreCache, 100, true, false, timeTolife, timeTolife));
cache = manager.getCache(nombreCache);
}

return cache;
}

public static void shutDown() {
CacheManager.getInstance().shutdown();
}

private int MINUTOS_DEFAULT = 60;

private static int minutosVidaDefault = 0;

protected CacheUtil(int minutosVida) {
minutosVidaDefault = minutosVida;
}

public static void init(int minutosVida) {
minutosVidaDefault = minutosVida;
}

/* * Constructor y accesores */

// Singleton Pattern private static CacheUtil singleton;

//Commons Logging Instance private Log log = LogFactory.getFactory().getInstance(this.getClass().getName());

/** * private constructor (just an instance). * @return AmbitoBO */ protected CacheUtil() throws ExcepcionServicio { super(); log.debug(“Creating a new instance of CacheUtil”); }

/**
* Devuelve instancia activa de AmbitoBO.
* Típico método de implementación de patrón singleton
* @return AmbitoBO
* @throws ExcepcionServicio
*/
public static CacheUtil getCurrentInstance() throws ExcepcionServicio {
if (singleton == null) {
try {
singleton = new CacheUtil();
} catch (ExcepcionServicio e) {
throw e;
}
}
return singleton;
}
}

Un saludo a todos, y poned una caché en vuestros corazones :-P

Contact

    La mejor solución de firma electrónica para tu empresa

    Update cookies preferences
    Scroll to Top