Reflexión Java: Proxies dinámicos

Con reflexión Java se crean implementaciones dinámicas de interfaces en tiempo de ejecución. Lo hace utilizando la clase java.lang.reflect.Proxy. El nombre de esta clase es por lo que me refiero a estas implementaciones de interfaces dinámicas como proxies dinámicos. Los proxies dinámicos se pueden usar para muchos propósitos diferentes, por ejemplo, conexión de bases de datos y administración de transacciones, objetos simulados dinámicos para pruebas unitarias y otros fines de interceptación de métodos similares a AOP.

Creación de Proxies

Puede crear proxies dinámicos utilizando el método Proxy.newProxyInstance(). Los métodos newProxyInstance() toman 3 parámetros:

  1. El ClassLoader que es “cargar” la clase proxy dinámica.
  2. Un conjunto de interfaces para implementar.
  3. Y InvocationHandler para reenviar todas las llamadas a métodos del proxy.

Este es un ejemplo:

Después de ejecutar este código, la variable proxy contiene una implementación dinámica de la interfaz MyInterface. Todas las llamadas al proxy se enviarán a la implementación handler de la interfaz general InvocationHandler. Los de invocación están cubiertos en la siguiente sección.

InvocationHandler

Como se mencionó anteriormente, debe pasar una implementación InvocationHandler al método Proxy.newProxyInstance(). Todas las llamadas a métodos al proxy dinámico se reenvían a esta implementación InvocationHandler. Así es como se ve la interfaz InvocationHandler :

public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object args) throws Throwable;}

Aquí hay un ejemplo de implementación:

public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object args) throws Throwable { //do something "dynamic" }}

El parámetro proxy pasado al método invoke() es el objeto proxy dinámico que implementa la interfaz. La mayoría de las veces no necesita este objeto.

El objeto Method pasado al método invoke() representa el método llamado en la interfaz que implementa el proxy dinámico. Desde el objeto Method puede obtener el nombre del método, los tipos de parámetros,el tipo de retorno, etc. Consulte el texto sobre Métodos para obtener más información.

El array Object args contiene los valores de parámetro pasados al proxy cuando se llamó al método en la interfaz implementada. Nota: Las primitivas (int, long, etc.)en la interfaz implementada están envueltas en sus contrapartes de objetos (Integer, Long, etc.).

Casos de uso conocidos

Se sabe que los proxies dinámicos se utilizan al menos para los siguientes fines:

  • Conexión de base de datos y Administración de Transacciones
  • Objetos Simulados Dinámicos para Pruebas unitarias
  • Adaptación del Contenedor DI a Interfaces de fábrica personalizadas
  • Interceptación de Métodos similares a AOP

Conexión de base de datos y Administración de transacciones

El framework Spring tiene un proxy de transacción que puede iniciar y confirmar / revertir una transacción por usted. Cómo funciona esto se describe con más detalle en el texto Conexión Avanzada y Demarcación y Propagación de Transacciones, por lo que solo lo describiré brevemente. La secuencia de llamadas se convierte en algo a lo largo de esto:

Objetos simulados dinámicos para Pruebas unitarias

Las herramientas de prueba Butterfly hacen uso de proxies dinámicos para implementar stubs dinámicos, simulaciones y proxies para pruebas unitarias. Al probar una clase A que usa otra clase B (interfaz realmente), puede pasar una implementación simulada de B a A en lugar de una B real. Ahora se graban todas las llamadas a métodos en B, y puede establecer qué valores de retorno devolverá el B falso.

Además, las herramientas de prueba Butterfly le permiten envolver un B real en un B simulado, de modo que todas las llamadas a métodos en el mock se graban y luego se reenvían al B real.Esto hace posible verificar qué métodos se llamaron en un B real que funciona. Por ejemplo, si prueba un DAO, puede envolver la conexión de la base de datos en un mock. El DAO no verá la diferencia, y el DAO puede leer / escribir datos en la base de datos como de costumbre, ya que el simulacro reenvía todas las llamadas a la base de datos. Pero ahora puede verificar a través del simulacro si el DAO usa la conexión correctamente, por ejemplo, si se llama (o NO se llama) a connection.close(), si lo esperaba. Esto normalmente no es posible de determinar a partir del valor de retorno de un DAO.

Adaptación del contenedor DI a Interfaces de fábrica personalizadas

El contenedor de inyección de dependencia Butterfly Container tiene una característica poderosa que le permite inyectar todo el contenedor en frijoles producidos por él. Pero, dado que no desea una dependencia de la interfaz del contenedor, el contenedor es capaz de adaptarse a una interfaz de fábrica personalizada de su diseño. Solo necesitas la interfaz. No se aplica. Por lo tanto, la interfaz de fábrica y su clase podrían verse algo como esto:

public interface IMyFactory { Bean bean1(); Person person(); ...}

Cuando la clase MyAction llama a los métodos de la instancia IMyFactory inyectada en su constructor por el contenedor, las llamadas al método se traducen en llamadas al método IContainer.instance(), que es el método que se utiliza para obtener instancias del contenedor. De esta manera, un objeto puede usar el contenedor Butterfly como una fábrica en tiempo de ejecución, en lugar de solo inyectarse dependencias en sí mismo en el momento de la creación. Y esto sin tener dependencias en ninguna interfaz específica de contenedor Butterfly.

Interceptación de métodos tipo AOP

El framework Spring permite interceptar llamadas de métodos a un bean dado, siempre que bean implemente alguna interfaz. El marco de primavera envuelve el frijol en un proxy dinámico. Todas las llamadas al bean son interceptadas por el proxy. El proxy puede decidir llamar a otros métodos en otros objetos antes, en lugar de, o después de delegar la llamada al método al bean wrapped.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.