manejo library cache borrar java servlets caching java-ee

borrar - java cache library



Aplicación web Java: ¿cómo implementar técnicas de almacenamiento en caché? (6)

Aquí hay un ejemplo de almacenamiento en caché con EhCache. Este código se usa en varios proyectos para implementar el almacenamiento en caché ad hoc.

1) Pon tu caché en el contexto global. (No olvide agregar el oyente en WEB.XML).

import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; public class InitializationListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); CacheManager singletonManager = CacheManager.create(); Cache memoryOnlyCache = new Cache("dbCache", 100, false, true, 86400,86400); singletonManager.addCache(memoryOnlyCache); cache = singletonManager.getCache("dbCache"); ctx.setAttribute("dbCache", cache ); } }

2) Recupere la instancia de caché cuando la necesite. es decir, desde un servlet:

cache = (Cache) this.getContext().getAttribute("dbCache");

3) Consulta el caché justo antes de realizar una operación costosa.

Element e = getCache().get(key); if (e != null) { result = e.getObjectValue(); // get object from cache } else { // Write code to create the object you need to cache, then store it in the cache. Element resultCacheElement = new Element(key, result); cache.put(resultCacheElement); }

4) Además, no olvide invalidar los objetos en caché cuando sea apropiado.

Puedes encontrar más muestras here

Estoy desarrollando una aplicación web Java que basa su comportamiento a través de grandes archivos de configuración XML que se cargan desde un servicio web. Como estos archivos no son realmente necesarios hasta que se accede a una sección particular de la aplicación, se cargan de forma perezosa. Cuando se requiere uno de estos archivos, se envía una consulta al servicio web para recuperar el archivo correspondiente. Como es probable que algunos de los archivos de configuración se usen mucho, con mucha más frecuencia que otros, me gustaría configurar algún tipo de almacenamiento en caché (con un tiempo de caducidad de aproximadamente 1 hora) para evitar solicitar el mismo archivo una y otra vez.

Los archivos devueltos por el servicio web son los mismos para todos los usuarios en todas las sesiones. No uso JSP, JSF o cualquier otro marco elegante, solo servlets simples.

Mi pregunta es, ¿qué se considera una mejor práctica para implementar un caché estático global en una aplicación web java? ¿Es apropiada una clase Singleton, o habrá comportamientos extraños debido a los contenedores J2EE? ¿Debo exponer algo en algún lugar a través de JNDI? ¿Qué debo hacer para que mi caché no se atornille en entornos agrupados (está bien, pero no es necesario, tener un caché por servidor agrupado)?

Dada la información anterior, ¿sería una implementación correcta poner un objeto responsable del almacenamiento en caché como un atributo ServletContext?

Nota: No quiero cargarlos todos al inicio y terminar con esto porque eso

1). sobrecargar el servicio web cada vez que se inicia mi aplicación
2). Los archivos pueden cambiar mientras mi aplicación se está ejecutando, por lo que tendría que volver a consultarlos de todos modos
3). Todavía necesitaría un caché accesible globalmente, por lo que mi pregunta aún se mantiene

Actualización: el uso de un proxy de almacenamiento en caché (como squid) puede ser una buena idea, pero cada solicitud al servicio web enviará consultas XML bastante grandes en los datos de la publicación, que pueden ser diferentes cada vez. Solo la aplicación web realmente sabe que dos llamadas diferentes al servicio web son en realidad equivalentes.

Gracias por tu ayuda


Bref, puedes utilizar esta configuración de ehcache de primavera preparada

1- ehcache.xml : muestra la configuración global de Ehcache.

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="./ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true" name="myCacheManager"> <!-- see ehcache-core-*.jar/ehcache-fallback.xml for description of elements Attention: most of those settings will be overwritten by hybris --> <diskStore path="java.io.tmpdir"/> </ehcache>

2- ehcache-spring.xml : crea EhCacheManagerFactoryBean y EhCacheFactoryBean.

<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" scope="singleton"> <property name="configLocation" value="ehcache.xml" /> <property name="shared" value="true" /> </bean> <bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean" scope="singleton"> <property name="cacheManager" ref="myCacheManager" /> <property name="cacheName" value="myCache" /> <property name="maxElementsInMemory" value="1000" /> <property name="maxElementsOnDisk" value="1000" /> <property name="eternal" value="false" /> <property name="diskPersistent" value="true" /> <property name="timeToIdle" value="600" /> <property name="timeToLive" value="1200" /> <property name="memoryStoreEvictionPolicy" value="LRU" /> <property name="statisticsEnabled" value="true" /> <property name="sampledStatisticsEnabled" value="true" /> </bean>

3- Inyecte el bean "myCache" en su clase de negocios, consulte el siguiente ejemplo para comenzar a obtener y colocar un objeto en su caché.

@Resource("myCache") private net.sf.ehcache.Cache myCache; @Resource("myService") private Service myService; public byte[] getFromCache(final String code) { // init Cache final StringBuilder builder = new StringBuilder(); // key to identify a entry in cache map final String key = code; // get form the cache final Element element = myCache.get(key); if (element != null && element.getValue() != null) { return (byte[]) element.getValue(); } final byte[] somethingToBeCached = myService.getBy(code); // store in the cache myCache.put(new Element(key, somethingToBeCached)); return somethingTobeCached; }


Después de mirar un poco más a mi alrededor, parece que la forma más fácil de lograr lo que necesito (dentro de los requisitos y las limitaciones aceptables descritas en la pregunta) sería agregar mi objeto de almacenamiento en caché al contexto del servlet y buscarlo (o pasándolo por ahí) donde sea necesario.

Simplemente crearía una instancia de mi cargador de configuración desde ServletContextListener, y dentro del método contextInitialized (), solo lo almacenaría en ServletContext usando ServletContext.setAttribute (). Entonces es fácil buscarlo desde los propios servlets usando request.getSession (). GetServletContext (). GetAttribute ().

Supongo que esta es la forma correcta de hacerlo sin introducir la primavera o cualquier otro marco de inyección de dependencia.


No tuve ningún problema al colocar una instancia de objeto en caché dentro de ServletContext. No olvide otras 2 opciones (alcance de solicitud, alcance de sesión) con los métodos setAttributes de estos objetos. Todo lo que se admite de forma nativa dentro de los contenedores web y los servidores j2ee es bueno (me refiero a que es independiente del proveedor y sin pesadas bibliotecas j2ee como Spring). Mi mayor exigencia es que los servidores se pongan en funcionamiento en 5-10 segundos.

Realmente no me gusta toda la solución de almacenamiento en caché, porque es muy fácil hacer que funcione en la máquina local, y es difícil hacer que funcione en las máquinas de producción. EHCACHE, Infinispan, etc. A menos que necesite una replicación / distribución amplia, estrechamente integrada con el ecosistema de Java, puede usar REDIS (base de datos NOSQL) o nodejs ... Cualquier cosa con la interfaz HTTP servirá. Especialmente

El almacenamiento en caché puede ser realmente fácil, y aquí está la solución java pura (sin marcos):

import java.util.*; /* ExpirableObject. Abstract superclass for objects which will expire. One interesting design choice is the decision to use the expected duration of the object, rather than the absolute time at which it will expire. Doing things this way is slightly easier on the client code this way (often, the client code can simply pass in a predefined constant, as is done here with DEFAULT_LIFETIME). */ public abstract class ExpirableObject { public static final long FIFTEEN_MINUTES = 15 * 60 * 1000; public static final long DEFAULT_LIFETIME = FIFTEEN_MINUTES; protected abstract void expire(); public ExpirableObject() { this(DEFAULT_LIFETIME); } public ExpirableObject(long timeToLive) { Expirer expirer = new Expirer(timeToLive); new Thread(expirer).start(); } private class Expirer implements Runnable { private long _timeToSleep; public Expirer (long timeToSleep){ _timeToSleep = timeToSleep; } public void run() { long obituaryTime = System.currentTimeMillis() + _timeToSleep; long timeLeft = _timeToSleep; while (timeLeft > 0) { try { timeLeft = obituaryTime - System.currentTimeMillis(); if (timeLeft > 0) { Thread.sleep(timeLeft); } } catch (InterruptedException ignored){} } expire(); } } }

Por favor, consulte este link para obtener más mejoras.


Tu pregunta contiene varias preguntas separadas juntas. Comencemos lentamente. ServletContext es un buen lugar donde puede almacenar el control de su caché. Pero pagas teniendo caché por instancia de servidor. No debería ser un problema. Si desea registrar el caché en un rango más amplio, considere registrarlo en JNDI.

El problema con el almacenamiento en caché Básicamente, estás recuperando xml a través de webservice. Si está accediendo a este servicio web a través de HTTP, puede instalar un servidor proxy HTTP simple de su lado que maneje el almacenamiento en caché de xml. El siguiente paso será el almacenamiento en caché de xml resuelto en algún tipo de caché de objetos locales. Este caché puede existir por servidor sin ningún problema. En este segundo caso, EHCache hará un trabajo perfecto. En este caso, la cadena de procesamiento será como esta Client - http request -> servlet -> look into local cache - if not cached -> look into http proxy (xml files) -> do proxy job (http to webservice) .

Pros:

  • Caché local por instancia de servidor, que contiene solo objetos de xmls solicitados
  • Un proxy http que se ejecuta en el mismo hardware que nuestra aplicación web.
  • Posibilidad de escalar webapp sin agregar nuevos proxies http para archivos xml.

Contras:

  • Siguiente nivel de infraestructura
  • +1 punto de falla (proxy HTTP)
  • Despliegue más complicado

Actualización: no olvide enviar siempre la solicitud HTTP HEAD al proxy para asegurarse de que la caché esté actualizada.


Opción n. ° 1: utilice una biblioteca de almacenamiento en caché de código abierto como EHCache

No implemente su propio caché cuando haya varias buenas alternativas de código abierto que pueda instalar y comenzar a usar. La implementación de su propio caché es mucho más compleja de lo que la mayoría de la gente cree y si no sabe exactamente qué está haciendo al enrutar, fácilmente comenzará a reinventar la rueda y a resolver algunos problemas muy difíciles.

Yo recomendaría EHCache, está bajo una licencia de Apache. Querrá echar un vistazo a las muestras del código de EHCace .

Opción n. ° 2: usar calamar

Una solución aún más fácil para su problema sería usar Squid ... Ponga Squid entre el proceso que solicita que los datos sean almacenados en caché y el sistema que realiza la solicitud: http://www.squid-cache.org/