1. Descripción general <Br /> Agente es un patrón de diseño, cuyo propósito es proporcionar a otro objeto un proxy para controlar el acceso a un determinado objeto. La clase proxy es responsable del preprocesamiento de mensajes para la clase delegada, filtrando mensajes y mensajes de reenvío, y realizar el procesamiento posterior después de que la clase delegada ejecute el mensaje. Para mantener la consistencia en el comportamiento, las clases proxy y las clases de delegado generalmente implementan la misma interfaz.
Según el período de creación de agentes, las clases de agentes se pueden dividir en dos tipos:
Proxy estático: el programador crea una clase proxy o una herramienta específica para generar automáticamente el código fuente y luego compilarlo. Es decir, el archivo .class de la clase proxy ya existe antes de que se ejecute el programa.
Proxy dinámico: use el mecanismo de reflexión para crear y generar dinámicamente cuando el programa se está ejecutando.
Presentemos brevemente el proxy estático antes de implementar el mecanismo de proxy dinámico.
2. Proxy estático <Br /> Como se mencionó anteriormente, tanto las clases de proxy como las clases de delegados generalmente necesitan implementar la misma interfaz. Lo siguiente es para definir esta interfaz primero:
Servicio de interfaz pública {public void add ();}La clase delegada es una implementación de una interfaz, definida de la siguiente manera:
Public Class ServiceImpl implementa el servicio {public void add () {System.out.println ("Agregar usuario!"); }}Si queremos agregar algunos registros a la clase delegada, la clase proxy se puede definir de la siguiente manera:
Servicio Public ClassProxy Implementa el servicio {Servicio de servicio privado; Public ServiceProxy (servicio de servicio) {super (); this.service = servicio; } public void add () {System.out.println ("Service Start"); servicio.Add (); System.out.println ("End de servicio"); }}Escribir clases de prueba:
public class testMain {public static void main (String [] args) {Service ServiceImpl = new ServiceImpl (); Servicio proxy = nuevo ServiceProxy (ServiceImpl); proxy.add (); }}Ejecute el programa de prueba, los resultados son los siguientes:
En el código anterior, podemos ver que la clase proxy estática solo puede servir una interfaz específica. Si desea servir múltiples tipos de objetos, debe presentar cada objeto. Pensaremos si todas las funciones de proxy se pueden completar a través de una clase de proxy, por lo que presentamos el concepto de proxy dinámico.
3. Proxy dinámico El proxy dinámico de Java involucra principalmente dos clases, proxy e invocationhandler.
Proxy: proporciona un conjunto de métodos estáticos para generar dinámicamente clases de proxy y sus objetos para un conjunto de interfaces.
// Método 1: Este método se utiliza para obtener el procesador de llamadas asociado con el objeto proxy especificado. Invocationhandler estático getInVocationHandler (Proxy de objeto) // Método 2: Este método se utiliza para obtener el objeto de clase de la clase dinámica proxy asociada con el cargador de clase especificado y un conjunto de interfaces. La clase estática getProxyClass (Classloader Loader, Class [] Interfaces) // Método 3: Este método se utiliza para determinar si el objeto de clase especificado es una clase proxy dinámica Boolean isProxyClass (clase CL) // Método 4: Este método se utiliza para generar casos proxy dinámicos para el cargador de clase especificado, un conjunto de interfaces interfaces y un conjunto de interfaces interfaces. Objeto estático NewProxyInstance (ClassLoader Loader, Interfaces de clase [], InvocationHandler H)
InvocationHandler: es una interfaz de procesador de llamadas, personaliza un método de Invok, que se utiliza para manejar centralmente las llamadas de método en objetos de clase de proxy dinámico, generalmente en los que se implementa el acceso proxy a las clases delegadas
// Este método es responsable de manejar centralmente todas las llamadas de método en la clase Dynamic Proxy. El primer parámetro es tanto una instancia de la clase proxy, y el segundo parámetro es el objeto del método que se llama // El tercer método es el parámetro de llamada. El procesador de llamadas preprocesos o envía a la instancia de la clase delegada para transmitir el objeto de ejecución Invoke (Object Proxy, Método Método, Objeto [] Args)
Para implementar proxy dinámico para Java, hay cuatro pasos específicos:
1. Cree su propio procesador de llamadas implementando la interfaz InvocationHandler
2. Cree una clase proxy dinámica especificando el objeto de carnero de clases y un conjunto de interfaces para la clase proxy
3. Obtenga el constructor de la clase proxy dinámica a través del mecanismo de reflexión, y su único tipo de parámetro es el tipo de interfaz de clase de procesador de llamadas
4. Cree una instancia de clase de proxy dinámica a través del constructor. Durante la construcción, el objeto del procesador se llama como parámetro y se pasa.
El siguiente es un ejemplo de implementación de su propio proxy dinámico en función de los cuatro pasos anteriores:
La clase de implementación de interfaz e interfaz (es decir, clase delegada) es la misma que el código del proxy estático anterior. Aquí implementaremos la interfaz InvocationHandler para crear nuestro propio procesador de llamadas.
Public Class ServiceHandle implementa InvocationHandler {Object privado s; Public ServiceHandle (Object s) {this.s = s; } Public Object Invoke (Object Proxy, Método Método, Object [] args) lanza lando {system.out.println ("Service Start"); // Invocar significa llamar al método subyacente representado por este objeto de método en un objeto especificado con parámetros especificados Objeto resultado = Method.Invoke (S, Args); System.out.println ("End de servicio"); resultado de retorno; }}Escribir clases de prueba:
public class testMain {public static void main (string [] args) {Service Service = new ServiceImpl (); InvocationHandler Handler = New ServiceHandle (Servicio); Servicio s = (servicio) proxy.newproxyInstance (Service.getClass (). GetClassLoader (), Service.getClass (). GetInterfaces (), Handler); S.Add (); }}Ejecute el programa de prueba, y el resultado es el mismo que el proxy estático. Podemos ver que el código anterior no tiene los pasos 2 y 3 que mencionamos antes, porque el método estático de Prox NewProxyInstance ha encapsulado estos dos pasos para nosotros. La implementación interna específica es la siguiente:
Crea dinámicamente dinámicamente un objeto de clase de la clase proxy para un conjunto de interfaces que incluye la interfaz de interfaz a través de proxy class clazz = proxy.getProxyClass (classloader, new class [] {interface.class, ...}); // obtenga el objeto de construcción del objeto de clase generado }); // Cree una instancia de clase proxy dinámica a través de la interfaz del objeto constructor proxy = (interface) constructor.newinstance (nuevo objeto [] {Handler});La implementación interna de la función NewProxyInstance es:
Public static Object NewProxyInstance (ClassLoader Loader, class <?> [] Interfaces, InvocationHandler H) arroja ilegalargumentException {// verificar h no está vacío, de lo contrario lanza objetos de excepción.requirenonnull (h); // Obtenga el objeto de tipo de clase proxy relacionado con la formulación del cargador de clase y un conjunto de interfaces de clase final <?> [] Intfs = interfaces.clone (); // Verifique si el objeto de clase de interfaz es visible para el cargador de clase y es exactamente el mismo que el objeto de clase de interfaz reconocido por el cargador de clase final SecurityManager SM = System.getSecurityManager (); if (sm! = null) {checkProxyAccess (Reflection.getCallerClass (), Loader, INTFS); } // Obtenga el objeto de tipo de clase proxy relacionado con la formulación del cargador de clase y un conjunto de interfaces clase <?> Cl = getProxyClass0 (cargador, intfs); Pruebe {if (sm! = null) {checknewproxyPermission (reflexion.getCallerClass (), cl); } // Obtenga el objeto Constructor a través de la reflexión y genere una instancia de clase proxy Constructor final <?> Cons = cl.getConstructor (constructorParams); InvocationHandler final IH = H; if (! Modifier.ispublic (cl.getModifiers ())) {accessController.Doprivileged (new PrivilegEdaction <Void> () {public void run () {cons.setAccessible (true); return null;}}); } return Cons.newinstance (nuevo objeto [] {h}); } Catch (ilegalAccessException | InstanciationException e) {tire new GonalError (e.ToString (), e); } catch (invocationTargetException e) {showable t = e.getCause (); if (t instanceOf runtimeException) {throw (runtimeException) t; } else {tirar nueva internalSorRor (t.ToString (), t); }} Catch (nosuchmethodexception e) {throw new GonalErsor (e.ToString (), e); }} 4. Simular e implementar la clase proxy
De acuerdo con la introducción del principio anterior, podemos simular e implementar la clase de proxy por nosotros mismos:
Public Class Proxy {Public Static Object NewProxyInstance (class Inface, InvocationHandle H) lanza la excepción {String rt = "/r/n"; String MethodStr = ""; Método [] métodos = inface.getMethods (); for (método m: métodos) {métodoStr+= "@anulación"+rt+"public void"+m.getName ()+"()"+rt+"{"+rt+"try {"+rt+"método md ="+inface.getName ()+". class.getMethod (/" "+m.getName ()+"/");"+R "H.invoke (this, md);"+ rt+ "} catch (excepción e) {E.PrintStackTrace ();}"+ rt+ "}"; } String src = "Test de paquete;"+ RT+ "Importar java.lang.reflect.method;"+ RT+ "Public Class ServiceImpl2 Implementa"+ inface.getName ()+ rt+ "{"+ rt+ "Servicio públicoMPL2 (InvocationHandle H)"+ RT+ "{"+ Rt+ "this.h;"+ "+"+ "+"+ "+"+ "+"+ "+"} test.InvocationHandle h; "+ RT+ Methodstr+"} "; Cadena filename = "d: /src/test/serviceImpl2.java"; // compilar compilar (src, nombre de archivo); // cargar en la memoria y crear objeto de instancia m = loadMemory (h); regresar m; } compilar void static privado (string src, string filename) lanza ioexception {archivo f = nuevo archivo (nombre de archivo); FileWriter FileWriter = new FileWriter (f); FileWriter.Write (SRC); FileWriter.flush (); FileWriter.Close (); // Obtenga el compilador Java proporcionado por esta plataforma, Javacompiler compiler = ToolProvider.getSystemJavacompiler (); // Obtenga una nueva instancia implementada por un administrador de archivos estándar StandardJavafilemanager Filemanager = compiler.getStandardFilemanager (NULL, NULL, NULL); // Obtener el objeto de archivo que representa el archivo dado iterable unidades = filemanager.getJavafileObjects (nombre de archivo); // Crear Task de compilación futura t = Compiler.getTask (NULL, FILEMANAGER, NULL, NULL, NULL, UNITS); // ejecutar esta tarea de compilación t.call (); Filemanager.close (); } LoadMemory de objeto estático privado (InvocationHandle H) lanza malformedurexception, classNotFoundException, nosuchmethodException, InstanciationException, ilegalAccessException, invocationTargetException {url [] urls = new url [] {new URL ("archivo:/"+"d:/src/")}; // Cargar clase y recursos URLClassLoader UL = new URLClassLoader (URLS); Clase C = Ul.LoadClass ("Test.ServiceImpl2"); // Devuelve el constructor público especificado de la clase representada por el objeto de clase. Constructor ctr = c.getConstructor (invocationHandle.class); // Use el método del constructor representado por este objeto de constructor CTR para crear una nueva instancia de la clase de declaración del método del constructor, e inicialice la instancia con el objeto de parámetro de inicialización especificado M = Ctr.newinstance (h); regresar m; }}5. Resumen 1. El llamado proxy dinámico es una clase así. Es una clase generada en tiempo de ejecución. Al generarlo, debe proporcionarle un conjunto de interfaces y luego cambiar la clase para afirmar que implementa estas interfaces. Sin embargo, no hará un trabajo sustancial para usted, pero se hará cargo del trabajo real basado en el controlador de parámetros (es decir, la clase de implementación de la interfaz InvocationHandler) proporcionada cuando genera la instancia.
2. El diseño del proxy hace que solo soporte el proxy de interfaz. El mecanismo de herencia de Java destinado a que la clase de proxy dinámica no pueda implementar proxy dinámico para la clase, porque la herencia múltiple esencialmente no es factible en Java.
Lo anterior se trata de este artículo, espero que sea útil para el aprendizaje de todos.