Francisco Javier Martínez Páez

Consultor tecnológico de desarrollo de proyectos informáticos.

 Ingeniero Técnico en Telecomunicaciones

Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación

Somos expertos en Java/J2EE

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2007-04-27

Tutorial visitado 20.791 veces Descargar en PDF
Patrón Proxy PATRÓN DE DISEÑO PROXY

Los ejemplos de este tutorial están hechos con el siguiente entorno de desarrollo:
  • Jboss Eclipse IDE.

  • JDK 1.5
INTRODUCCIÓN

Desde hace unos años están apareciendo gran cantidad de herramientas que introducen nuevos conceptos como la orientación a aspectos (AOP),  la interceptación, etc... .  En el fondo, todas ellas están basadas en algo no tan nuevo como es el patrón Proxy.  Podríamos definir un proxy, como un objeto que fuerza que todas las llamadas al objeto al que se desea invocar  pasen previamente a través de él. Esto nos permite realizar acciones que podríamos llamar transversales a la funcionalidad realizada por el objeto final invocado, como por ejemplo, trazabilidad, seguridad, transaccionalidad etc... . Es decir, si por ejemplo nosotros invocamos al método sayHello del objeto obj de la clase Saludo, podríamos "interceptar" esa llamada a través del Proxy, para comprobar si realmente el que invoca al método tiene permisos para realizar la acción, sin tener que modificar para ello el método sayHello . En esto se basan gran cantidad de herramientas como Spring, Acegi, la arquitectura de EJBs de gran cantidad de servidores de aplicaciones como JBoss, etc.

Para ello, usaremos la clase java.lang.reflect.Proxy que lleva ya con nosotros desde la versión 1.3 de la J2SE.

Sin más, vamos a realizar un ejemplo sencillo, para demostrar todo esto:

EL EJEMPLO

Nos crearemos un proyecto nuevo en nuestro Eclipse, y generaremos primero un Interfaz que denominaremos Manager, que define toda la funcionalidad que preveemos puede tener la lógica de negocio de las clases de nuestra aplicación:

package com.autentia.adictos.proxy;

public interface Manager {
    public void save(Object obj);
    public void remove(Integer id);    


Vamos a construir ahora una clase implemente el interfaz:

package com.autentia.adictos.proxy;

public class UserManagerImpl implements Manager {

    public void save(Object obj) {       
        System.out.println("I save user Objects");
    }

    public void remove(Integer id) {
        System.out.println("I remove user objects");
    }

}

Vamos ahora a contruir el Manejador o Handler, que será el que será previamente invocado a los métodos de los managers:

package com.autentia.adictos.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ManagerHandler implements InvocationHandler {
   
    Manager realManager = null;
   
    public ManagerHandler(Manager realManager) {
        this.realManager = realManager;
    }
   
    /* Este es el método callback que será invocado previamente a cada método de          los managers. */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {       

       
        System.out.println("A Manager is being invoked:"+method.getName());

       
        // Continuamos invocando al Manager real.
        return method.invoke(realManager,args);
    }

}

Ahora crearemos una Factor�a de Managers, que creará los mismos encapsulados dentro de un Proxy:

package com.autentia.adictos.proxy;

import java.lang.reflect.Proxy;

public class FactoryManager {
   
        public Manager createManager(Class claseManager) {
            
            Manager realManager = null;
           
            try {
                // Creamos un objeto de la clase que recibimos.
                realManager = (Manager)claseManager.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
           
          /* Creamos el CallBack Handler y le pasamos el objeto real para ser invocado               posteriormente
en su método invoke. */
         
            ManagerHandler handler = new ManagerHandler(realManager);
           
            // Creamos el proxy.
            Class[] interfacesQueEncapsulo = new Class[] {Manager.class};   
            return (Manager)Proxy.newProxyInstance(
                           claseManager.getClassLoader(),
                            interfacesQueEncapsulo,handler);
                  
        }     
}

Creamos una clase para probar lo que hemos hecho:

package com.autentia.adictos.proxy;

public class Test {
   
    public static void main(String[] args) {
        // Creamos ahora la factoria
        FactoryManager factory = new FactoryManager();
       
        // Usamos la factoria para crear un Proxy sobre UserManagerImpl
        Manager manager = factory.createManager(UserManagerImpl.class);
       
        Object obj = new Object();
        // Invocamos a los métodos:
        manager.save(obj);
        manager.remove(1);
       
    }

}

Mostremos la salida estándar:


Salida estándar


Como podéis ver, el código del Handler es invocado previamente al código del UserManagerImpl. Curioso ¿no?.  ¿Os suena esto ?. Supongo que si conocías ya el tema de AOP, AspectJ etc..., verás que se parece sospechosamente. Ahora, en el manejador podríamos trazar lo que ocurre, o guardar en base de datos un registro, o autenticar o autorizar, o abrir una transacción, invocar al método y cerrar una transacción, etc...  Suponed éste código:


    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {        

        
        openTransaction();        

        
        Object obj =  method.invoke(realManager,args);
      
        closeTransaction();       

        
        return obj;
    }


Creo que esto habla por sí s�lo.

El único problema es que el hacer que nuestros Managers implementen un interfaz es algo rígido, por eso es mejor usar frameworks que nos proporcionan todo esto de una manera más flexible, como Spring, Acegi, EJB 3.0 etc..., pero creo que es más bonito conocer como se hacen las herramientas o en que se basan antes de usarlas, y no creer que es magia....







A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Fecha publicación: 2013-04-18-19:09:48

Autor: devoured

Excelente ejemplo, muchas gracias. Realmente no está tan obvio, pero tampoco no está difícil nada que no arregle un hora de debuggear.

Fecha publicación: 2009-06-02-03:32:32

Autor:

[Fenix] Está bueno el ejemplo, aunque falta más explicación del mismo. El hecho que tu lo entiendas, y que creas que el código habla por si solo, no quiere decir q todos lo veamos de la misma forma.