Para fazer proxy de uma classe com proxy dinâmico jdk, a classe com proxy deve implementar pelo menos uma interface e apenas os métodos na interface podem ser proxy.
A implementação do proxy dinâmico no jdk é geralmente dividida em três etapas:
1. Escreva interfaces e classes de implementação.
2. Escreva um processador que implemente a interface InvocationHandler. Esta interface possui apenas um método e sua assinatura é public Object Invoke (Object proxy, Method method, Object[] args).
throws Throwable; Você pode adicionar seu próprio código no método de implementação do processador antes e depois da chamada do método para realizar a interceptação dinâmica. Deve-se notar que a classe de proxy dinâmica gerada pelo proxy não é a classe real que estamos proxy, então podemos adicionar uma variável de membro do tipo Object ao processador para apontar para a classe que realmente queremos que seja proxy (ou seja, o classe na classe de implementação da etapa 1).
3. Use o método newProxyInstance da classe java.lang.reflect.Proxy para gerar uma classe de proxy dinâmica. Para todas as chamadas de métodos proxy, você pode chamar diretamente o método da classe proxy dinâmica gerada, mas primeiro deve realizar uma conversão forçada de tipo nele e convertê-lo na interface do método que queremos chamar.
Análise do princípio JDK:
Ao analisar o código-fonte do Proxy, você pode ver a geração detalhada de classes de proxy dinâmicas. O método newProxyInstance primeiro gera uma instância Class da classe de proxy dinâmico e, em seguida, chama seu construtor cujo tipo de parâmetro é InvocationHandler para gerar a classe de proxy dinâmico e retornar.
Como gerar a instância Class da classe proxy dinâmica A classe ProxyGenerator é usada para gerar o fluxo de bytes da classe proxy dinâmica e carregá-lo na área do método.
Analisando o processo de geração de fluxo de bytes da classe, podemos ver que ele usa Proxy como sua classe pai para implementar todos os métodos da interface a serem proxy. O corpo de implementação de cada método chama principalmente o método de invocação do processador.
O código principal do processo de geração de fluxo de bytes de classe é o seguinte:
Copie o código do código da seguinte forma:
byte privado[] gerarClassFile()
{
addProxyMethod(hashCodeMethod, java/lang/Object);
addProxyMethod(equalsMethod, java/lang/Object);
addProxyMethod(toStringMethod, java/lang/Object);
for(int i = 0; i < interfaces.length; i++)
{
Método amethod[] = interfaces[i].getMethods();
for(int k = 0; k < um método.comprimento; k++)
addProxyMethod(amethod[k], interfaces[i]);
}
Lista de lista;
for(Iterador iterador = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(lista))
lista = (Lista)iterator.next();
tentar
{
métodos.add(generateConstructor());
for(Iterador iterador1 = proxyMethods.values().iterator(); iterador1.hasNext();)
{
Lista lista1 = (Lista)iterator1.next();
Iterador iterador2 = list1.iterator();
enquanto(iterador2.hasNext())
{
ProxyMethod proxymethod = (ProxyMethod)iterator2.next();
campos.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
métodos.add(<SPAN style="COLOR: red">proxymethod.generateMethod()</SPAN><SPAN style="COLOR: #000000">);</SPAN>
Copie o código do código da seguinte forma:
}
}
métodos.add(generateStaticInitializer());
}
catch(IOException ioexception)
{
throw new InternalError("Exceção de E/S inesperada");
}
if(métodos.size() > 65535)
throw new IllegalArgumentException("limite do método excedido");
if(campos.size() > 65535)
throw new IllegalArgumentException("limite de campo excedido");
cp.getClass(dotToSlash(className));
cp.getClass("java/lang/reflect/Proxy");
for(int j = 0; j < interfaces.length; j++)
cp.getClass(dotToSlash(interfaces[j].getName()));
cp.setReadOnly();
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
DataOutputStream dataoutputstream = novo DataOutputStream(bytearrayoutputstream);
tentar
{
dataoutputstream.writeInt(-889275714);
dataoutputstream.writeShort(0);
dataoutputstream.writeShort(49);
cp.write(dataoutputstream);
dataoutputstream.writeShort(49);
dataoutputstream.writeShort(cp.getClass(dotToSlash(className)));
dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
dataoutputstream.writeShort(interfaces.comprimento);
for(int l = 0; l < interfaces.length; l++)
dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName())));
dataoutputstream.writeShort(fields.size());
FieldInfofieldinfo;
Copie o código do código da seguinte forma:
//Adiciona atributos
for(Iterador iterador3 = campos.iterator(); iterador3.hasNext(); fieldinfo.write(dataoutputstream))
fieldinfo = (FieldInfo)iterator3.next();
//Adiciona método
dataoutputstream.writeShort(métodos.size());
MethodInfométodoinfo;
for (Iterador iterador4 = métodos.iterator(); iterador4.hasNext(); methodinfo.write(dataoutputstream))
methodinfo = (MethodInfo)iterator4.next();
dataoutputstream.writeShort(0);
}
catch(IOException ioexception1)
{
throw new InternalError("Exceção de E/S inesperada");
}
retornar bytearrayoutputstream.toByteArray();
}
Nota: A parte vermelha do código, proxymethod.generateMethod(), gera o corpo do método para cada método. Observando o código-fonte, podemos ver que todos eles estão chamando o método de invocação do processador de implementação da interface InvocationHandler.