OSCache: Sistema de caché para aplicaciones Java

2
21822

OSCache: Sistema de caché para aplicaciones Java

Índice de contenido

Introducción

Normalmente hay secciones y datos dentro de nuestras aplicaciones que no varían con frecuencia o cuya frecuencia está controlada y es conocida.
Además, obtener esta información es costosa en tiempo o recursos informáticos.. pues bien, es obvio que si cacheamos esta información el rendimiento de nuestra aplicación incrementará
y por lo tanto la satisfacción de los usuarios que la utilizan también mejorará.

En este tutorial vamos a ver uno de los sistemas de caché más extendidos y aceptados, se trata de OSCache


Caso de estudio: Aplicación de escritorio

A continuación, vamos a programar una sencilla aplicación de escritorio en donde aprenderemos a realizar las tareas de cacheo, descacheo y acceso a la información cacheada. Se trata de una sencilla aplicación en donde cada operación se realiza al hacer clic en un botón, y en donde se mostrará el tiempo que transcurre desde que se inicia la tarea hasta que finaliza. Para ello, se simula el acceso a una fuente de datos cuyo costo en tiempo es bastante elevado, por lo que decidimos cachearlo.

La intención de esta sencilla aplicación es que aprenda y observe lo que va sucediendo al acceder a datos cacheados, acceder a datos que no han sido cacheados, etc.

Configuración de OSCache para este ejemplo

OSCache se configura fácilmente a través de un archivo de configuración de nombre oscache.properties.

Aunque para usarlo no hay por que tocar nada, en este tutorial vamos a cambiar el comportamiento de por defecto (cache en memoria sin límite en el número de elementos a cachear) para habilitar el cacheo en disco,
de manera que si la aplicación se cierra no haya que volver a cachear los datos.

Desde mi punto de vista las propiedades que he modificado son las más importantes, así que observe los comentarios para conocer su significado.

# Habilitamos el cache en disco      
cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener

# Especificamos el directorio donde se cacheará la información
cache.path=c:\\oscache_temp

# Indicamos que queremos un límite también para los elementos cacheados en disco 
cache.unlimited.disk=false

# Como mucho serán cacheados 500 objetos simultánemente
cache.capacity=500

# Cuando se supere el límite de 500 objetos, se aplicará el algoritmo LRU (Least Recently Used) para obtener espacio en disco y cachear los nuevos elementos.
cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache
    

Para más información dirigase a la documentación de configuración oficial.

Código fuente de la aplicación:

La siguiente clase simula un acceso lento (2 segundos) para obtener una información que luego será cacheada.

package com.autentia.tutoriales.oscache;

/**
 * Gestión de clientes.
 * Simula accesos lentos a los datos. 
 * @author Carlos García. Autentia.
 * @see http://www.mobiletest.es  
 */
public class CustomersCtrl {
	
	private CustomersCtrl(){}
	
	/**
	 * @return Devuelve todos los clientes
	 */
	public static java.util.ArrayList getAll(){
		java.util.ArrayList customers = new java.util.ArrayList();
		
		for (int i = 0; i < 5; i++){
			customers.add("Cliente " + String.valueOf(i));
		}

		// Retrasamos la ejecución, simulando una operación costosa en tiempo
		try {
			Thread.sleep(2000);
		} catch (java.lang.InterruptedException ex){
			// No hacemos nada.
		}	
		
		return customers;
	}
}
    
    

La siguiente clase representa una ventana con distintos botones cuyas tareas estarán realicionadas con operaciones con la caché.

package com.autentia.tutoriales.oscache;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;

import javax.swing.*;

import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.opensymphony.oscache.web.filter.ExpiresRefreshPolicy;
import com.opensymphony.oscache.base.NeedsRefreshException;

/**
 * Ventana para probar el API de OScache
 * @author Carlos García. Autentia.
 * @see http://www.mobiletest.es
 */
public class OSCacheTestFrame extends JFrame implements java.awt.event.ActionListener {
	
	private static final String ALL_CUSTOMER_CACHE_KEY = "CUSTOMERS";

	// Atributos funcionales
	private GeneralCacheAdministrator cache;
	private ArrayList		  customers;
	
	// Atributos gráficos
	private JLabel  lblTime;
	private JPanel  contentPane;
	private JPanel  buttons;
	private JButton btnAppendDataToCache;
	private JButton btnReadFromCache;
	private JButton btnDeleteCache;
	
	/**
	 * Constructor
	 */
	public OSCacheTestFrame(){
		super("Pruebas con OScache");
		
		cache = new GeneralCacheAdministrator();
		
		this.createUI();
	}

	/**
	 * Crea el interfaz gráfico
	 */
	private void createUI() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception ex) {
			//No se dará
		}
		
		lblTime		= new JLabel();
		contentPane = new JPanel(new BorderLayout());
		buttons	  	= new JPanel(new FlowLayout());
		
		btnAppendDataToCache = new JButton("Cachear datos");
		btnReadFromCache	 = new JButton("Leer datos");
		btnDeleteCache		 = new JButton("Borrar cache");
		
		contentPane.add(lblTime, BorderLayout.NORTH);
		contentPane.add(buttons, BorderLayout.SOUTH);
		
		buttons.add(btnReadFromCache);
		buttons.add(btnAppendDataToCache);
		buttons.add(btnDeleteCache);
		
		btnAppendDataToCache.addActionListener(this);
		btnReadFromCache.addActionListener(this);
		btnDeleteCache.addActionListener(this);
		
		this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		this.setSize(new Dimension(400, 200));
		this.setContentPane(contentPane);
	}
	
	/* Tareas de liberación de recursos
	 * @see java.awt.Window#dispose()
	 */
	public void dispose() {
		super.dispose();
		cache.destroy();
	}
	
	/**
	 * Intenta leer los datos de la caché. En caso de que no exista los lee de la "base de datos"
	 */
	private void readFromCacheTask() {
		 try {
			customers = (ArrayList ) cache.getFromCache(ALL_CUSTOMER_CACHE_KEY);
		} catch (NeedsRefreshException e) { // Los datos de la cache no existen o han caducado
			cache.cancelUpdate(ALL_CUSTOMER_CACHE_KEY);
			customers =  CustomersCtrl.getAll();
		}
	}

	/**
	 * Añade datos a la cache con un período de validez de 120 segundos
	 */
	private void putDataOnCacheTask(){
		customers =  CustomersCtrl.getAll();
		cache.putIncache(ALL_CUSTOMER_cache_KEY, customers, new ExpiresRefreshPolicy(120));
	}

	/**
	 * Vacia la cache
	 */
	private void deleteCacheTask() {
		cache.removeEntry(ALL_CUSTOMER_CACHE_KEY);
	}
	
	/* 
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent evt) {
		Object source 	 = evt.getSource();
		boolean isError	 = false;
		long   startTime = System.currentTimeMillis();
		
		try {
			// Todas las tareas deberían realizarse en un hilo independiente para no 
			// bloquear el hilo principal de repintado
			if (source == btnReadFromCache){
				readFromCacheTask();	 
			} else if (source == btnDeleteCache){
				deleteCacheTask();	
			} else if (source == btnAppendDataToCache){
				putDataOnCacheTask();
			}
		} catch (Exception ex){
			isError	 = true;
			JOptionPane.showMessageDialog(this, ex.getMessage());
		} finally {
			if (! isError){
				lblTime.setText("Tiempo en realizar la tarea " + (System.currentTimeMillis() - startTime) +  " milisegundos");				
			}
		}
	}

	/**
	 * Inicia el programa de testeo del API OSCache 
	 */
	public static void main(String[] args) {
		JFrame appWin = new OSCacheTestFrame();
		appWin.setVisible(true);
	}
}
    
    

Si observa la configuración de OSCache para esta aplicación, la caché en disco está habilitada, de manera que en la siguiente imagen se puede observar como OSCache crea y destruye los archivos en donde guarda la información cacheada:

Nota: Al estar habilitada la cache en disco, si cierra la aplicación y la vuelve abrir verá que los datos sigen estando cacheados, es decir, los tiempos de lectura tienden a cero.
(En este caso la cache tiene un tiempo de validez de 120 segundos desde que fué cacheada).

Caso de estudio: Aplicación Web.

OScache, además de ser un sistema de cache de propósito general sobre el cuál podemos cachear objetos. Incluye una librería de Tags y un filtro que proporcionan de forma sencilla la posibilidad de cachear secciones o páginas completas de JSP de nuestras aplicaciones Web.

Si desea más información al respecto, le recomiendo que lea el siguiente tutorial. Ver el tutorial.

Referencias a otros sistemas de caché Open Source

El siguiente enlace se enumeran otros sistemas de caché Open Source:

Open Source cache Solutions in Java

Conclusiones

Bueno como veis es bastante sencillo de integrar en nuestras aplicaciones y las mejoras de rendimiento pueden ser notables.. Eso sí, para la gente nueva en este tema, conviene profundizar más al respecto y elegir bien los puntos estratégicos a cachear.

Carlos García Pérez. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.

cgpcosmad@gmail.com

2 COMENTARIOS

  1. amigo mucha gracias por la Información, me surge una pregunta: Tengo una aplicación de Escritorio en Java SE (Swing) donde se conecta a un DB en un CPANEL de MySql, todo funciona perfecto; pero cuando se cae el Internet, muere la aplicación… con este método puedo hacer que guarde en caché, que conserve los consecutivos, la data etc … y que luego valide si hay internet y procesa a sincronizar ?

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad