Proxy din谩mico de Java: 驴qu茅 es y c贸mo usarlo?

Hola a todos!

Bueno, antes del A帽o Nuevo y el inicio de la d茅cima transmisi贸n, el "Desarrollador Java" est谩 bromeando por completo. As铆 que tenemos una lecci贸n abierta que estamos preparando para su publicaci贸n y la nota de hoy, de la que aprender谩 sobre el proxy din谩mico de Java: qu茅 es, cu谩ndo y c贸mo usarlo en el c贸digo.

驴Qu茅 es un proxy?

Un proxy es un patr贸n de dise帽o. Lo creamos y lo usamos para agregar y cambiar la funcionalidad de las clases existentes. En este caso, se usa el objeto proxy en lugar del original. Por lo general, utiliza el mismo m茅todo que el original, y en Java las clases proxy ampl铆an las originales. Un proxy puede invocar un m茅todo en el objeto fuente ya que tiene un descriptor original.

Por lo tanto, las clases proxy implementan convenientemente muchas cosas:

  • registrar el inicio y la detenci贸n del m茅todo;
  • verificaci贸n adicional de argumentos;
  • imitaci贸n del comportamiento de la clase fuente;
  • implementaci贸n de inicializaci贸n diferida de recursos costosos;



Todo esto sucede sin cambiar el c贸digo de clase original. La lista completa no se limita a los ejemplos anteriores, son solo una peque帽a parte de ella.

En la pr谩ctica, la clase proxy no implementa directamente la funcionalidad. Siguiendo el principio de responsabilidad exclusiva, la clase proxy realiza directamente solo proxy y los cambios de comportamiento se implementan en los controladores. Al llamar a un objeto proxy en lugar del original, el proxy decide si llama al m茅todo original o a algunos controladores. El controlador puede realizar su propia tarea y hacer referencia al m茅todo original.

Aunque el patr贸n proxy no solo se usa para crear un objeto proxy y una clase en el tiempo de ejecuci贸n, en Java este es un tema particularmente interesante. En este art铆culo, me centro en tales poderes.

Este es un tema complejo que requiere el uso de una clase de reflexi贸n, o manipular bytecode, o compilar c贸digo Java generado din谩micamente. O tal vez todo a la vez. Para evitar que la nueva clase est茅 disponible como bytecode en tiempo de ejecuci贸n, se requerir谩 el bytecode generado y el cargador de clases para cargar el bytecode. Para crear bytecode, use cglib , bytebuddy o el compilador Java incorporado.

La importancia de la separaci贸n de responsabilidades, en nuestro caso, queda clara, solo necesita pensar en las clases proxy y los controladores que llaman. Se genera una clase proxy en tiempo de ejecuci贸n, pero los controladores que llama pueden agregarse al c贸digo fuente normal y compilarse con el resto del programa.

驴C贸mo usarlo en nuestro c贸digo?

Lo m谩s simple es usar java.lang.reflect.Proxy , que es parte del JDK. Esta clase puede crear una clase proxy o su instancia directamente. Usar un proxy integrado en Java es muy simple. Todo lo que necesita hacer es implementar java.lang.InvocationHandler para que el objeto proxy pueda llamarlo. La interfaz InvocationHandler es extremadamente simple y contiene solo un m茅todo: invoke() . Cuando se llama, los argumentos contienen el objeto original proxy, el m茅todo llamado (como un reflejo del objeto Method ) y una matriz de objetos de los argumentos originales. El fragmento de c贸digo siguiente muestra la aplicaci贸n:

 package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JdkProxyDemo { interface If { void originalMethod(String s); } static class Original implements If { public void originalMethod(String s) { System.out.println(s); } } static class Handler implements InvocationHandler { private final If original; public Handler(If original) { this.original = original; } public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { System.out.println("BEFORE"); method.invoke(original, args); System.out.println("AFTER"); return null; } } public static void main(String[] args){ Original original = new Original(); Handler handler = new Handler(original); If f = (If) Proxy.newProxyInstance(If.class.getClassLoader(), new Class[] { If.class }, handler); f.originalMethod("Hallo"); } } 

Para llamar al m茅todo original del objeto fuente, el controlador necesita acceso a 茅l. Lo que no proporciona la implementaci贸n del proxy Java. Deber谩 pasar el argumento usted mismo a la instancia del controlador en el c贸digo. (Preste atenci贸n al objeto (generalmente llamado proxy), que se pasa como un argumento al manejador llamado. Este es un objeto proxy que Java genera din谩micamente, y no el objeto que queremos proxy). Por lo tanto, puede usarlo por separado objetos de controlador para cada clase de origen, as铆 como un objeto general que sabe c贸mo llamar al objeto original, si hay alg煤n m茅todo para esto.

En el caso especial, puede crear un controlador de llamadas y una interfaz proxy sin el objeto original. Adem谩s, no se requiere una clase para implementar una interfaz en el c贸digo fuente. Se implementa mediante una clase proxy creada din谩micamente.

Si la clase proxy no implementa la interfaz, deber铆a considerar usar alguna otra implementaci贸n de proxy.

El fin

Esperando sus comentarios y preguntas. Como siempre, aqu铆, o puedes ir a Vitaly para un d铆a abierto .

Source: https://habr.com/ru/post/es434214/


All Articles