Para representar una clase con proxy dinámico jdk, la clase representada debe implementar al menos una interfaz, y solo se pueden representar métodos en la interfaz.
La implementación del proxy dinámico en jdk generalmente se divide en tres pasos:
1. Escribir interfaces y clases de implementación.
2. Escriba un procesador que implemente la interfaz InvocationHandler. Esta interfaz tiene solo un método y su firma es invocación de objeto público (proxy de objeto, método de método, argumentos de objeto []).
throws Throwable; puede agregar su propio código en el método de implementación del procesador antes y después de la llamada al método para realizar la interceptación dinámica. Cabe señalar que la clase de proxy dinámico generada por el proxy no es la clase real que estamos representando, por lo que podemos agregar una variable miembro de tipo Objeto al procesador para que apunte a la clase que realmente queremos que sea proxy (es decir, la clase de proxy dinámica generada por el proxy). clase en la clase de implementación del paso 1).
3. Utilice el método newProxyInstance de la clase java.lang.reflect.Proxy para generar una clase de proxy dinámica. Para todas las llamadas a métodos proxy, puede llamar directamente al método de la clase proxy dinámica generada, pero primero debe realizar una conversión de tipo forzada y convertirlo en la interfaz del método que queremos llamar.
Análisis del principio JDK:
Al analizar el código fuente de Proxy, puede ver la generación detallada de clases de proxy dinámicas. El método newProxyInstance primero genera una instancia de clase de la clase de proxy dinámico y luego llama a su constructor cuyo tipo de parámetro es InvocationHandler para generar la clase de proxy dinámico y regresar.
¿Cómo generar la instancia de clase de la clase de proxy dinámico? La clase ProxyGenerator se utiliza para generar el flujo de bytes de clase de la clase de proxy dinámico y cargarlo en el área de métodos.
Al analizar el proceso de generación de flujo de bytes de clase, podemos ver que utiliza Proxy como su clase principal para implementar todos los métodos de la interfaz a ser proxy. El cuerpo de implementación de cada método llama principalmente al método de invocación del procesador.
El código principal del proceso de generación del flujo de bytes de clase es el siguiente:
Copie el código de código de la siguiente manera:
byte privado[] generarClassFile()
{
addProxyMethod(hashCodeMethod, java/lang/Object);
addProxyMethod(equalsMethod, java/lang/Object);
addProxyMethod(toStringMethod, java/lang/Object);
para(int i = 0; i < interfaces.length; i++)
{
Método amethod[] = interfaces[i].getMethods();
for(int k = 0; k < amétodo.longitud; k++)
addProxyMethod(método[k], interfaces[i]);
}
Lista de lista;
for(Iterador iterador = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(lista))
lista = (Lista)iterador.siguiente();
intentar
{
métodos.add(generateConstructor());
for(Iterador iterador1 = proxyMethods.values().iterator(); iterator1.hasNext();)
{
Lista lista1 = (Lista)iterator1.next();
Iterador iterador2 = lista1.iterador();
mientras (iterador2.hasNext())
{
ProxyMethod proxymethod = (ProxyMethod)iterator2.next();
campos.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
métodos.add(<SPAN style="COLOR: rojo">proxymethod.generateMethod()</SPAN><SPAN style="COLOR: #000000">);</SPAN>
Copie el código de código de la siguiente manera:
}
}
métodos.add(generateStaticInitializer());
}
captura (IOException ioexcepción)
{
lanzar un nuevo error interno ("excepción de E/S inesperada");
}
si(métodos.tamaño() > 65535)
lanzar nueva IllegalArgumentException ("límite de método excedido");
si(campos.tamaño() > 65535)
lanzar nueva IllegalArgumentException ("límite de campo excedido");
cp.getClass(dotToSlash(nombredeclase));
cp.getClass("java/lang/reflect/Proxy");
para(int j = 0; j < interfaces.length; j++)
cp.getClass(dotToSlash(interfaces[j].getName()));
cp.setReadOnly();
ByteArrayOutputStream bytearrayoutputstream = nuevo ByteArrayOutputStream();
DataOutputStream dataoutputstream = nuevo DataOutputStream(bytearrayoutputstream);
intentar
{
flujo de salida de datos.writeInt(-889275714);
flujo de salida de datos.writeShort(0);
flujo de salida de datos.writeShort(49);
cp.write(flujo de salida de datos);
flujo de salida de datos.writeShort(49);
dataoutputstream.writeShort(cp.getClass(dotToSlash(className)));
dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
dataoutputstream.writeShort(interfaces.length);
for(int l = 0; l < interfaces.length; l++)
dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName())));
dataoutputstream.writeShort(fields.size());
Información de campo información de campo;
Copie el código de código de la siguiente manera:
//Añadir atributos
for(Iterator iterator3 = campos.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream))
información de campo = (FieldInfo)iterator3.next();
//Añadir método
dataoutputstream.writeShort(methods.size());
MethodInfo información del método;
for(Iterador iterador4 = métodos.iterador(); iterador4.hasNext(); métodoinfo.write(flujo de salida de datos))
métodoinfo = (MethodInfo)iterator4.next();
flujo de salida de datos.writeShort(0);
}
captura (IOException ioexcepción1)
{
lanzar un nuevo error interno ("excepción de E/S inesperada");
}
devolver bytearrayoutputstream.toByteArray();
}
Nota: La parte roja del código, proxymethod.generateMethod(), genera el cuerpo del método para cada método. Al observar el código fuente, podemos ver que todos están llamando al método de invocación del procesador de implementación de la interfaz InvocationHandler.