Olá pessoal!
Bem, antes do Ano Novo e do início do décimo fluxo, o
"Desenvolvedor Java" está brincando. Portanto, temos uma lição aberta que estamos preparando para publicação e o artigo de hoje, do qual você aprenderá sobre o proxy Java dinâmico: o que é, quando e como usá-lo no código.
O que é um proxy?Um proxy é um padrão de design. Nós o criamos e usamos para adicionar e alterar a funcionalidade das classes existentes. Nesse caso, o objeto proxy é usado em vez do original. Normalmente, ele usa o mesmo método que o original e, nas classes proxy Java, estende as classes originais. Um proxy pode chamar um método no objeto de origem, pois possui um descritor original.
Assim, as classes proxy implementam convenientemente muitas coisas:
- registrando o início e a parada do método;
- verificação adicional de argumentos;
- imitação do comportamento da classe fonte;
- implementação de inicialização diferida de recursos dispendiosos;

Tudo isso acontece sem alterar o código da classe original. A lista completa não se limita aos exemplos acima, eles são apenas uma pequena parte dela.
Na prática, a classe proxy não implementa diretamente a funcionalidade. Seguindo o princípio de responsabilidade exclusiva, a classe proxy executa diretamente apenas proxy e as mudanças de comportamento são implementadas nos manipuladores. Ao chamar um objeto proxy em vez do original, o proxy decide se deve chamar o método original ou alguns manipuladores. O manipulador pode executar sua própria tarefa e se referir ao método original.
Embora o padrão de proxy não seja usado apenas para criar um objeto e uma classe de proxy no tempo de execução, em Java, este é um tópico particularmente interessante. Neste artigo, concentro-me em tais proxies.
Este é um tópico complexo que requer o uso da classe de reflexão, manipulação do bytecode ou compilação de código Java gerado dinamicamente. Ou talvez de uma só vez. Para impedir que a nova classe esteja disponível como bytecode no tempo de execução, o bytecode e o classloader gerados serão necessários para carregar o bytecode. Para criar bytecode, use
cglib ,
bytebuddy ou o compilador Java
interno .
A importância da separação de responsabilidades, no nosso caso, fica clara, você só precisa pensar nas classes de proxy e nos manipuladores que eles chamam. Uma classe de proxy é gerada em tempo de execução, mas os manipuladores que chama podem ser adicionados ao código-fonte regular e compilados com o restante do programa.
Como usá-lo em nosso código?
O mais simples é usar o
java.lang.reflect.Proxy
, que faz parte do JDK. Essa classe pode criar uma classe proxy ou sua instância diretamente. Usar um proxy embutido em Java é muito simples. Tudo o que você precisa fazer é implementar o
java.lang.InvocationHandler
para que o objeto proxy possa chamá-lo. A interface
InvocationHandler
é extremamente simples e contém apenas um método:
invoke()
. Quando chamados, os argumentos contêm o objeto original em proxy, o método chamado (como um reflexo do objeto
Method
) e uma matriz de objetos dos argumentos originais. O trecho de código abaixo demonstra o aplicativo:
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 chamar o método original do objeto de origem, o manipulador precisa ter acesso a ele. O que não é fornecido pela implementação do proxy Java. Você precisará passar o argumento você mesmo para a instância do manipulador no código. (Preste atenção ao objeto (geralmente chamado proxy), que é passado como argumento para o manipulador chamado. Este é um objeto proxy que o Java gera dinamicamente, e não o objeto que queremos proxy.) Assim, você pode usá-lo como separado objetos manipuladores para cada classe de origem, bem como um objeto geral que saiba como chamar o objeto original, se houver algum método para isso.
No caso especial, você pode criar um manipulador de chamadas e uma interface proxy sem o objeto original. Além disso, uma classe para implementar uma interface no código fonte não é necessária. É implementado por uma classe de proxy criada dinamicamente.
Se a classe em proxy não implementar a interface, considere usar alguma outra implementação de proxy.
O FIM
Aguardando seus comentários e perguntas. Como sempre, aqui, ou você pode ir a
Vitaly para um
dia aberto .