English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Retrofit es un framework de solicitudes de red altamente decoupled, y recientemente, mientras investigaba, descubrí una técnica muy poderosa y práctica llamada proxy dinámico. Este artículo servirá como conocimiento previo de Retrofit para que todos conozcan: ¿Cuáles son las aplicaciones del proxy dinámico, qué es el proxy dinámico, cómo se utiliza y dónde radica su limitación?
Escenarios de aplicación de la representación dinámica
1. AOP—Programación orientada a aspectos, desacoplamiento del programa
En resumen, cuando quieras hacer operaciones comunes antes y después de algunos métodos internos de una clase, mientras se ejecutan operaciones personalizadas en el método--Usa la representación dinámica. Puede reducir la cantidad de código y mejorar la mantenibilidad en situaciones con grandes volúmenes de negocio.
2. Quiero personalizar ciertos métodos de una biblioteca de terceros
He citado una biblioteca de terceros, pero algunos de sus métodos no satisfacen mis necesidades, quiero reescribir algunos de ellos o agregar algunas operaciones especiales antes y después de ellos--Usa la representación dinámica. Pero ten en cuenta que estos métodos tienen limitaciones, lo explicaré más tarde.
¿Qué es la representación dinámica
La imagen anterior es demasiado abstracta, comencemos con un ejemplo de la vida real.
Supongamos que eres un gran propietario (representado), tienes muchas propiedades que alquilar y no te gustaría manejarlas tú mismo, por lo que contratas a alguien para que lo haga por ti (representante), ayudándote a gestionar这些东西, y esta persona (representante, también intermediario) te cobra ciertos honorarios de intermediación (operaciones adicionales de alquiler de propiedades). Para el inquilino, el intermediario es el propietario, representándote en ciertas tareas.
En resumen, este es un ejemplo de representación, y por qué se llama "representación dinámica", ¿dónde se manifiestan las palabras "dinámico"?
Podemos pensar así, si tienes un representante para cada propiedad, cada vez que quieras alquilar una nueva propiedad necesitas contratar a otro representante, por lo que contratarás muchos representantes, lo que lleva a costos de intermediación altos, esto se puede considerar como el llamado "representación estática".
Pero si dejamos que todos los inmuebles sean gestionados por un intermediario que se cambie dinámicamente entre múltiples propiedades, ayudándote a manejar a cada inquilino. Esto es un proceso de "representación dinámica". Una de las características principales de la representación dinámica es que no hay clase de representación en la fase de compilación, sino que se crea en tiempo de ejecución.
Veamos un fragmento de código para entender
Operaciones de alquiler de casa
/** *Definir un contrato **/ public interface AlquilarCasa { void rent();//Alquiler de casa void charge(String str);//Cobro de alquiler }
Landlord
public class PropietarioCasa implements AlquilarCasa { public void rent() { System.out.println("Quiero alquilar mi casa"); } public void charge(String str) { System.out.println("Obtienes : ", + str + "CasaCobro."); } }
Agency
public class DynamicProxy implements InvocationHandler { // Este es el objeto real que queremos proxyar, es decir, el propietario de la casa private Object subject; // Método de construcción, asignar el valor inicial del objeto real que queremos proxyar public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Antes de proxyar el objeto real, también podemos agregar algunas operaciones propias, la agencia cobra la tarifa de agencia System.out.println("before "+method.getName()+" house"); System.out.println("Method:") + method.getName()); // Si el método es charge, la agencia cobra100 yuan agency fee. if (method.getName().equals("charge")) { method.invoke(subject, args); System.out.println("I will get 100 RMB ProxyCharge."); } else { // Cuando el objeto agente llama al método del objeto real, automáticamente salta al método invoke del objeto agente asociado para llamar method.invoke(subject, args); } // Después de proxyar el objeto real, también podemos agregar algunas operaciones propias System.out.println("after "+method.getName()+" house"); return null; } }
Guest
public class Client { public static void main(String[] args) { // El objeto real que queremos代理--Landlord HouseOwner houseOwner = new HouseOwner(); // El objeto real que queremos代理,lo pasamos aquí y finalmente llamamos a sus métodos a través de este objeto real InvocationHandler handler = new DynamicProxy(houseOwner); /* * Creamos nuestro objeto de agente a través del método newProxyInstance de Proxy, veamos sus tres parámetros * El primer parámetro handler.getClass().getClassLoader(), aquí usamos el objeto ClassLoader de la clase handler para cargar nuestro objeto proxy * El segundo parámetro realSubject.getClass().getInterfaces(), aquí proporcionamos las interfaces al objeto de proxy, que son las interfaces que realiza el objeto real, lo que significa que quiero代理该真实对象, de esta manera puedo llamar a los métodos de este grupo de interfaces * El tercer parámetro handler, aquí asociamos este objeto de proxy al objeto InvocationHandler superior */ RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner .getClass().getInterfaces(), handler);//Una clase de proxy dinámico, intermediario System.out.println(rentHouse.getClass().getName()); rentHouse.rent(); rentHouse.charge("10000"); } }
Vamos a ver la salida
com.sun.proxy.$Proxy0 before rent house Método:rent Quiero alquilar mi casa after rent house before charge house Método:charge Tú obtienes : 10000 RMB HouseCharge. I will get 100 RMB ProxyCharge. after charge house Proceso finalizado con código de salida 0
En la salida hay before rent house y after rent house, lo que significa que podemos agregar operaciones antes y después del método. Además, veamos la salida I will get 100 RMB ProxyCharge. La intermediación cobró100 bloques de tarifas de intermediación, lo que significa que no solo podemos agregar operaciones, sino que también podemos reemplazar este método o incluso hacer que este método no se ejecute.
Al principio, al ver el código, es posible que tengas muchas dudas, pero a través del siguiente contenido, veremos cómo utilizar el proxy dinámico.
¿Cómo se utiliza el proxy dinámico?
En el mecanismo de proxy dinámico de Java, hay dos clases e interfaces importantes: uno es InvocationHandler (Interface), y el otro es Proxy (Class), estas clases e interfaces son necesarias para implementar nuestro proxy dinámico.
Cada clase de proxy dinámico debe implementar la interfaz InvocationHandler (intermediario en el código), y cada instancia de la clase de proxy se asocia con un handler. Cuando llamamos a un método a través del objeto proxy, la llamada al método se reenvía a la llamada al método invoke (donde se escribe el增强 de métodos) de la interfaz InvocationHandler.
Object invoke(Object proxy, Method method, Object[] args) lanza Throwable
Vemos que este método acepta tres parámetros, ¿entonces, ¿qué representan estos tres parámetros?
Object invoke(Object proxy, Method method, Object[] args) lanza Throwable //proxy: representa el objeto real que estamos proxyando //method: representa el objeto Method que queremos llamar en el objeto real //args: representa los parámetros aceptados al llamar a un método de un objeto real
Vamos a ver la clase Proxy a continuación
public static Object newProxyInstance(ClassLoader loader, Class<63;][] interfaces, InvocationHandler h) lanza IllegalArgumentException
La clase Proxy se utiliza para crear dinámicamente un objeto proxy, proporciona muchos métodos, pero el que más utilizamos es newProxyInstance:
public static Object newProxyInstance(ClassLoader loader, Class<63;][] interfaces, InvocationHandler h) lanza IllegalArgumentException
El propósito de este método es obtener un objeto proxy dinámico, que recibe tres parámetros, veamos cuál es el significado de estos tres parámetros
public static Object newProxyInstance(ClassLoader loader, Class<63;][] interfaces, InvocationHandler h) lanza IllegalArgumentException //loader: un objeto ClassLoader, que define cuál objeto ClassLoader se utilizará para cargar el objeto proxy generado //interfaces: una matriz de objetos Interface, que representa qué tipo de interfaces proporcionaré a los objetos que necesitarán ser proxy, si les proporciono un grupo de interfaces, entonces el objeto proxy declarará que ha implementado la interfaz (polimorfismo), de esta manera podré llamar a los métodos de este grupo de interfaces //h: un objeto InvocationHandler, que representa que cuando este objeto de proxy dinámico llama a un método, se asociará con qué objeto InvocationHandler
De esta manera, combinando el código proporcionado anteriormente, podemos entender el método de uso del proxy dinámico
Limitaciones del proxy dinámico
Desde el método de uso del proxy dinámico podemos ver que todos los métodos que pueden ser fortalecidos son implementados por intermediarios (también se pueden usar métodos públicos sin implementar intermediarios mediante la herencia de la clase proxy), el código en HouseOwner hereda RentHouse. ¡Pero el proxy dinámico de JDK no puede hacer nada con los métodos privados!
Los proxies dinámicos mencionados anteriormente son de JDK, para proyectos java hay también el famoso CGLib, pero desafortunadamente CGLib no puede ser utilizado en android, el motor de virtualización de android es diferente del jvm.
Conclusión
El uso de proxy dinámico no se limita a estas escenas, los principios internos se presentarán en artículos futuros, pero el mecanismo de generación temporal de clases proxy de tipo reflexivo determina que tendrá un impacto en el rendimiento. Este artículo como artículo previo al principio de retrofit no es demasiado detallado, si hay errores o omisiones, bienvenidos a corregir!
Esto es todo el contenido de este artículo, espero que haya sido útil para su aprendizaje y que todos nos apoyen en el tutorial de alarido.
Declaración: Este artículo se ha obtenido de la red, es propiedad del autor original, el contenido ha sido contribuido y subido por usuarios de Internet de manera autónoma, este sitio web no posee los derechos de propiedad, no ha sido editado por humanos y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de violación de derechos de autor, le invitamos a enviar un correo electrónico a: notice#w.3Aviso: Este contenido se ha obtenido de la red, es propiedad del autor original, el contenido ha sido subido por usuarios de Internet de manera autónoma, este sitio web no posee los derechos de propiedad, no ha sido editado por humanos y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de violación de derechos de autor, le invitamos a enviar un correo electrónico a: notice#w proporcionando evidencia relevante, una vez que se verifique, este sitio eliminará inmediatamente el contenido sospechoso de violación de derechos de autor.