A chave para implementar o proxy dinâmico em Java são essas duas coisas: proxy e invasorhandler. Vamos começar com o método Invoke na interface InvocationHandler e explicar brevemente como o Java implementa o proxy dinâmico.
Primeiro, o formulário completo do método Invoke é o seguinte:
Public Object Invoke (proxy do objeto, método do método, objeto [] args) lança arremesso {métod.invoke (obj, args); retornar nulo;}Primeiro, vamos adivinhar que o método é o método chamado, ou seja, o método que precisa ser executado; args é o parâmetro do método; Proxy, o que é esse parâmetro? A implementação acima do método Invoke () é um formulário relativamente padrão. Vemos que nenhum parâmetros de proxy é usado aqui. Confira a descrição do proxy na documentação do JDK, como segue:
Uma invocação de método em uma instância de proxy através de uma de suas interfaces de proxy será despachada para o método de invocamento do manipulador de invocação da instância, passando na instância do proxy, a java.lang.reflect.method Object Identificando o método que foi invocado e uma matriz de objeto de tipo que contém os argumentos.
A partir disso, podemos saber que o palpite acima está correto e também sabemos que o parâmetro proxy é uma instância da classe proxy.
Por conveniência de explicação, aqui está um exemplo simples para implementar proxy dinâmico.
// Função abstrata (proxy dinâmico pode apenas interface proxy) }
// Função real: implementou o método request () da classe pública de disciplina realSubject implementa o assunto {public void request () {System.out.println ("do assunto real."); }} // implementa a classe de invocationHandler public dynamicsubject implementa InvocationHandler {objeto privado obj; // Este é o benefício do proxy dinâmico. O objeto encapsulado é do tipo de objeto e aceita objetos de qualquer tipo public dynamicsubject () {} public dynamicsubject (object obj) {this.obj = obj; } // Este método não é o que mostramos chamar de objeto público invoke (proxy do objeto, método do método, objeto [] args) lança arremesso {System.out.println ("antes de chamar" + método); método.invoke (obj, args); System.out.println ("depois de chamar" + método); retornar nulo; }} // cliente: gerar uma instância de proxy e chamar o método request () public class Client {public static void main (string [] args) lança arremesso {// TODO Auto-Gerated Method Stub STUB RS = new RealSubject (); // Especifique a classe de procuração InvocationHandler DS = novo DynamicSject (RS); Classe <?> Cls = rs.getclass (); // a seguir é uma geração única de sujeito proxy sujeito = (sujeito) proxy.NewProxyInstance (cls.getclassLoader (), cls.getInterfaces (), ds); // Aqui você pode provar que o assunto é uma instância de proxy executando os resultados. Esta instância implementa o sistema de interface do sujeito.out.println (instância de sujeito de proxy); // Aqui você pode ver que a classe do sujeito é $ proxy0. Essa classe $ proxy0 herda o proxy e implementa o sistema de interface de sujeito.out.println ("classe do sujeito é:"+sujeito.getclass (). Tostring ()); System.out.print ("As propriedades no assunto são:"); Campo [] campo = sujeito.getClass (). GetDecLaredFields (); for (campo f: campo) {System.out.print (f.getName ()+","); } Os métodos em System.out.print ("/n"+"sujeitos são:"); Método [] método = sujeito.getClass (). GetDecLaredMethods (); for (método m: método) {System.out.print (m.getName ()+","); } A classe pai do System.out.println ("/n"+"sujeito é:"+sujeito.getclass (). GetSuperclass ()); System.out.print ("/n"+"o sujeito implementa a interface:"); Classe <?> [] Interfaces = sujeito.getClass (). GetInterfaces (); para (classe <?> i: interfaces) {System.out.print (i.getName ()+","); } System.out.println ("/n/n"+"o resultado da execução é:"); sujeito.Request (); }} O resultado da operação é o seguinte: o nome do pacote é omitido aqui, *** em vez disso
verdadeiro
A classe de classe de assunto é: classe $ proxy0
As propriedades do assunto são: M1, M3, M0, M2,
Os métodos no assunto são: solicitação, hashcode, igual, tostring,
A classe pai do sujeito é: classe java.lang.reflect.proxy
A interface implementada pelo assunto é: cn.edu.ustc.dynamicproxy.subject,
O resultado da operação é:
Antes de ligar para o abstrato público vazio ***.
Do assunto real.
Depois de ligar para o abstrato público vazio ***.
PS: As informações sobre esse resultado são muito importantes, pelo menos para mim. Como a causa raiz da minha tontura no proxy dinâmico é que eu entendi mal o sujeito acima. Uma vez fiquei confuso sobre como a última solicitação de chamada () foi conectada ao Invoke () e como a Invoke sabia que a solicitação existe. De fato, True e Classe $ proxy0 acima podem resolver muitas perguntas e, juntamente com o código -fonte de $ proxy0 que será mencionado abaixo, ele pode resolver completamente as dúvidas de proxy dinâmico.
A partir do código e dos resultados acima, podemos ver que não chamamos o método Invoke () como mostrado, mas esse método foi executado. Vamos analisar todo o processo abaixo:
A julgar pelo código no cliente, você pode usar o método NewProxyInstance como um avanço. Vamos primeiro olhar para o código -fonte do método NewProxyInstance na classe Proxy:
Objeto estático público NewProxyInstance (ClassLoader carregador, classe <?> [] interfaces, InvocationHandler h) lança ilegalArgumentException {if (h == null) {lança new NullPointerException (); } / * * Procure ou gerar a classe proxy projetada. */ Classe cl = getProxyclass (carregador, interfaces); / * * Invoque seu construtor com o manipulador de invocação projetado. * / try { / * * O código -fonte proxy tem a seguinte definição: * classe estática final privada [] construtorParams = {InvocationHandler.class}; * CONS é o método do construtor com os parâmetros formais do tipo InvocationHandler*/ Constructor CONS = cl.getConstructor (constructorporams); return (object) cont.newInstance (novo objeto [] {h}); } catch (noschmethodException e) {tiro o novo internalError (e.toString ()); } catch (ilegalAccessException e) {tiro o novo internalError (e.toString ()); } catch (instantiationException e) {lança o novo internalError (e.toString ()); } catch (InvocationTargeTexception e) {THREN NOVO RENTERROR (E.ToString ()); }} Proxy.NewProxyInstance (Classloader carregador, classe <?> [] Interfaces, InvocationHandler H) as seguintes coisas.
(1) Chame o método getProxyclass (carregador, interfaces) com base no carregador e interfaces dos parâmetros, crie a classe Proxy Class $ proxy0.
(2) Instanciar $ proxy0 e passa em dinâmico, no construtor, então $ proxy0 chama o construtor do proxy da classe pai e atribui um valor a h, como segue:
classe Proxy {InvocationHandler H = null; Proxy protegido (InvocationHandler H) {this.h = h; } ...}Vamos dar uma olhada no código -fonte que herda o $ proxy0 da proxy:
Classe final pública $ proxy0 estende a proxy implementa o assunto {Método estático privado m1; Método estático privado m0; Método estático privado m3; Método estático privado m2; static {try {m1 = classe.ForName ("java.lang.object"). getMethod ("equals", nova classe [] {classe.ForName ("java.lang.Object")}); m0 = classe.ForName ("java.lang.object"). getMethod ("hashcode", nova classe [0]); m3 = classe.ForName ("***. RealSubject"). getMethod ("solicitação", nova classe [0]); m2 = classe.ForName ("java.lang.object"). getMethod ("tostring", nova classe [0]); } catch (noschmethodException noschmethodException) {tiro novo noschmethoderror (noschmethodException.getMessage ()); } Catch (ClassNotFoundException ClassNotFoundException) {THLHET NEW NOCLASSDEFFONDERROR (ClassNotFoundException.getMessage ()); }} // estático public $ proxy0 (InvocationHandler InvocationHandler) {super (InvocationHandler); } @Override public final boolean é igual (object obj) {try {return ((boolean) super.h.invoke (this, m1, novo objeto [] {obj})) .BooleanValue (); } catch (arremesso de arremesso) {lança uma nova não declaração de abordagem (jogável); }} @Override public final int hashCode () {try {return ((integer) super.h.invoke (this, m0, null)). Intvalue (); } catch (arremesso de arremesso) {lança uma nova não declaração de abordagem (jogável); }} public final void request () {try {super.h.invoke (this, m3, null); retornar; } catch (error e) {} catch (arremesso de arremesso) {tiro novo und -glearthrowableException (jogável); }} @Override public final string tostring () {try {return (string) super.h.invoke (this, m2, null); } catch (arremesso de arremesso) {lança uma nova não declaração de abordagem (jogável); }}}Em seguida, envie a instância de $ proxy0 resultante em um assunto e atribua a referência ao assunto. Quando o método sujeito.Request () é executado, o método request () na classe $ proxy0 é chamado, e o método Invoke () de H no proxy da classe pai é chamado. Isto é, invocationhandler.invoke ().
PS: 1. Uma coisa a observar é que o método getProxyclass na classe Proxy retorna a classe de proxy da classe. A razão para isso é que cometi um erro de baixo nível no início, pensando que o retorno é "classe de classe da classe de proxy"-! Recomenda -se dar uma olhada no código -fonte do getProxyclass, que é muito longo =. =
2. A partir do código -fonte de $ proxy0, pode -se observar que a classe dinâmica de proxy não apenas proxies os métodos na interface definida pela tela, mas também proxies os três métodos herdados de igual (), hashcode () e tostring () no objeto de classe raiz de java e apenas esses três métodos.
P: Até agora, ainda há uma pergunta. O primeiro parâmetro no método Invoke é uma instância de proxy (para ser preciso, a instância de $ proxy0 é finalmente usada), mas qual é o uso? Ou, como a função aparece no programa?
R: Do meu nível atual, esse parâmetro proxy não tem efeito. Em todo o mecanismo dinâmico de proxy, o parâmetro proxy do método Invoke no InvocationHandler não é usado. O parâmetro passado é realmente uma instância da classe proxy. Eu acho que pode ser para permitir que os programadores usem a reflexão no método Invoke para obter algumas informações sobre a classe proxy.
Resumir
O exposto acima é o conteúdo inteiro deste artigo sobre o método Invoke () no InvocationHandler. Espero que seja útil para todos. Amigos interessados podem continuar se referindo a este site:
Explicação detalhada do proxy estático da primavera e código dinâmico de proxy
Exemplo de método de injeção de dependência da estrutura da mola
Implementação de programação Java de Springmvc Simple Login Exemplo
Se houver alguma falha, deixe uma mensagem para apontá -la.