1. Visão geral <Br /> agente é um padrão de design, cujo objetivo é fornecer a outro objeto um proxy para controlar o acesso a um determinado objeto. A classe Proxy é responsável por pré -processamento de mensagens para a classe Delegate, filtrando mensagens e encaminhamento de mensagens e executando o processamento subsequente após a execução da mensagem pela classe Delegate. Para manter a consistência no comportamento, as classes de proxy e as classes delegadas geralmente implementam a mesma interface.
De acordo com o período da criação de agentes, as classes dos agentes podem ser divididas em dois tipos:
Proxy estático: o programador cria uma classe proxy ou uma ferramenta específica para gerar automaticamente o código -fonte e compilá -lo. Ou seja, o arquivo .class da classe de proxy já existe antes que o programa seja executado.
Proxy dinâmico: use o mecanismo de reflexão para criar e gerar dinamicamente quando o programa estiver em execução.
Vamos apresentar brevemente o proxy estático antes de implementar o mecanismo dinâmico de proxy.
2. Proxy estático <r />, como mencionado acima, as classes de proxy e as classes delegadas geralmente precisam implementar a mesma interface. O seguinte é definir esta interface primeiro:
Serviço de interface pública {public void add ();}A classe Delegate é uma implementação de uma interface, definida da seguinte forma:
public class ServiceImpl implementa o serviço {public void add () {System.out.println ("Adicionar usuário!"); }}Se quisermos adicionar alguns logs à classe Delegate, a classe Proxy pode ser definida da seguinte forma:
classe pública ServiceProxy implementa o serviço {Serviço privado; public ServiceProxy (serviço de serviço) {super (); this.Service = Service; } public void add () {System.out.println ("Start de serviço"); Service.add (); System.out.println ("End Service End"); }}Escreva aulas de teste:
classe pública testMain {public static void main (string [] args) {serviço serviceImpl = new ServiceImpl (); Proxy de serviço = new ServiceProxy (ServiceImpl); proxy.add (); }}Execute o programa de teste, os resultados são os seguintes:
A partir do código acima, podemos ver que a classe de proxy estática pode servir apenas uma interface específica. Se você deseja servir a vários tipos de objetos, deve procurar cada objeto. Pensaremos se todas as funções de proxy podem ser concluídas por meio de uma classe de proxy, por isso introduzimos o conceito de proxy dinâmico.
3. O proxy dinâmico de proxy dinâmico Java envolve principalmente duas classes, proxy e invasorhandler.
Proxy: fornece um conjunto de métodos estáticos para gerar dinamicamente classes de proxy e seus objetos para um conjunto de interfaces.
// Método 1: Este método é usado para obter o processador de chamada associado ao objeto proxy especificado. Invocação estática GetInvocationHandler (proxy de objeto) // Método 2: Este método é usado para obter o objeto de classe da classe de proxy dinâmica associada ao carregador de classe especificado e a um conjunto de interfaces. Classe estática getProxyclass (carregador de classe, interfaces de classe []) // Método 3: Este método é usado para determinar se o objeto de classe especificado é um dinâmico da classe de proxy dinâmico ISProxyclass (classe CL) // Método 4: esse método é usado para gerar uma classe dinâmica de instalações para o conjunto de classes especificadas. Objeto estático NewProxyInstance (Classloader carregador, Class [] Interfaces, InvocationHandler H)
InvocationHandler: É uma interface de processador de chamada, personaliza um método Invok, usado para lidar centralmente em chamadas de método em objetos dinâmicos de classe de proxy, geralmente no qual o acesso de proxy às classes delegadas é implementado
// Este método é responsável por lidar centralmente em todos os pedidos de método na classe dinâmica de proxy. O primeiro parâmetro é uma instância da classe proxy, e o segundo parâmetro é o objeto de método chamado // O terceiro método é o parâmetro de chamada. O processador de chamada pré -processos ou despacha para a instância da classe Delegate para transmitir o objeto de execução Invoke (proxy do objeto, método do método, objeto [] args)
Para implementar proxy dinâmico para Java, existem quatro etapas específicas:
1. Crie seu próprio processador de chamada implementando a interface InvocationHandler
2. Crie uma classe de proxy dinâmica especificando o objeto de classe de classe e um conjunto de interfaces para a classe proxy
3. Obtenha o construtor da classe dinâmica de proxy através do mecanismo de reflexão, e seu único tipo de parâmetro é o tipo de interface da classe de processador de chamada
4. Crie uma instância de classe de proxy dinâmica através do construtor. Durante a construção, o objeto do processador é chamado de parâmetro e é passado.
A seguir, é apresentado um exemplo de implementação de seu próprio proxy dinâmico com base nas quatro etapas acima:
A classe de implementação de interface e interface (ou seja, classe Delegate) é a mesma que o código do proxy estático acima. Aqui, implementaremos a interface InvocationHandler para criar nosso próprio processador de chamadas.
classe pública ServiceHandle implementa a InvocationHandler {Private Object S; public ServiceHandle (objeto s) {this.s = s; } Public Object Invoke (proxy do objeto, método do método, objeto [] args) lança arremesso {System.out.println ("Start Start"); // Invoke significa chamar o método subjacente representado por esse objeto Método em um objeto especificado com parâmetros especificados, resultado do objeto = method.invoke (s, args); System.out.println ("End Service End"); resultado de retorno; }}Escreva aulas de teste:
classe pública testMain {public static void main (string [] args) {Service Service = new ServiceImpl (); Handler de InvocationHandler = new ServiceHandle (Service); Serviço s = (serviço) proxy.newProxyInstance (service.getclass (). GetClassloader (), service.getclass (). GetInterfaces (), manipulador); s.add (); }}Execute o programa de teste e o resultado é o mesmo que o proxy estático. Podemos ver que o código acima não possui as etapas 2 e 3 mencionamos antes, porque o método estático da Prox NewProxyInstance encapsulou essas duas etapas para nós. A implementação interna específica é a seguinte:
// Crie dinamicamente um objeto de classe da classe proxy para um conjunto de interfaces, incluindo a interface da interface através da classe proxy clazz = proxy.getproxyclass (classloader, nova classe [] {interface.class, ...}); // obtenha o objeto de construtor do objeto Gerado (construtor de classes = (}); }); // Crie uma instância dinâmica da classe proxy através da interface do objeto construtor proxy = (interface) construtor.newInstance (new Object [] {Handler});A implementação interna da função NewProxyInstance é:
Objeto estático público NewProxyInstance (ClassLoader carregador, classe <?> [] interfaces, InvocationHandler h) lança ilegalArgumentException {// check h não está vazio; caso contrário, lança excepcionários.RequirenOnNull (h); // Obtenha o objeto de tipo de classe proxy relacionado à formulação do carregador de classe e um conjunto de interfaces da classe final <?> [] Intfs = interfaces.clone (); // Verifique se o objeto da classe de interface é visível para o carregador de classe e é exatamente o mesmo que o objeto da classe de interface reconhecido pelo carregador de classe Final SecurityManager SM = System.getSecurityManager (); if (sm! = null) {checkProxyAccess (refletion.getCalerClass (), carregador, intfs); } // Obtenha o objeto Tipo de classe de proxy relacionado à formulação do carregador de classe e um conjunto de interfaces de classe <?> Cl = getProxyclass0 (carregador, intfs); tente {if (Sm! } // Obtenha o objeto do construtor por meio de reflexão e gerar uma instância da classe proxy Final Constructor <?> CONS = cl.getConstructor (constructorParams); Invocação final IH = H; if (! modifier.ispublic (cl.getModifiers ())) {AccessController.Doprivileged (novo privilegiado <Void> () {public void run () {Cons.SetAccessible (true); return null;}}); } return conts.newInstance (novo objeto [] {h}); } catch (ilegalAccessException | InstantionException e) {Troque o novo InternError (e.toString (), e); } catch (InvocationTargeTexception e) {throwable t = e.getCausa (); if (t instanceof runTimeException) {throw (runTimeException) t; } else {lança novo internalError (t.toString (), t); }} Catch (noschmethodException e) {tiro o novo internalError (e.toString (), e); }} 4. Simule e implemente a classe de proxy
De acordo com a introdução do princípio acima, podemos simular e implementar a classe de proxy por nós mesmos:
classe pública proxy {public static objeto newproxyInstance (classe inface, invocationhandle h) lança exceção {string rt = "/r/n"; String Methodstr = ""; Método [] Métodos = Inface.getMethods (); para (Método M: Métodos) {MethodStr+= "@Substitua"+rt+"public void"+m.getName ()+"()"+rt+"{"+rt+"try {"+rt+"método md ="+inface.getname ()+". "h.invoke (this, md);"+ rt+ "} catch (Exceção e) {e.printStackTrace ();}"+ rt+ "}"; } String src = "teste do pacote;"+ rt+ "importar java.lang.reflect.method;"+ rt+ "classe pública ServiceImpl2 implementos"+ inface.getName ()+ rt+ "{"+ rt+ "public ServiceImpl2 (InvocationHandle H)"+ rt+ "{" "+ rt+" Rt+ ". test.invocationHandle H; "+ RT+ MethodStr+"} "; String filename = "d: /src/test/serviceImpl2.java"; // compilar compilar (src, nome do arquivo); // carrega na memória e crie o objeto de instância m = loadMemory (h); retornar m; } Compile de void estático privado (string src, string filename) lança IoException {arquivo f = new File (nome do arquivo); FileWriter fileWriter = new FileWriter (f); fileWriter.Write (SRC); fileWriter.flush (); fileWriter.close (); // Obtenha o compilador Java fornecido por esta plataforma, Javacompiler compilador = ToolProvider.getSystemJavacompiler (); // obtenha uma nova instância implementada por um gerenciador de arquivos padrãojavafilemanager FileManager = Compiler.getStandardFilemanager (NULL, NULL, NULL); // Obtenha o objeto Arquivo que representa o arquivo iteável unidades = FileManager.getJavafileObjects (nome do arquivo); // Crie Future CompilationTask t = Compiler.getTask (NULL, FileManager, NULL, NULL, NULL, Units); // execute esta tarefa de compilação t.call (); FileManager.close (); } Private Static Object LoadMemory (InvocationHandle H) lança malformedurlexception, classNotFoundException, NoschmethodException, InstantiationException, ilegalAccessException, InvocationTarGetexception {url [] URLS = new Url [] {New Url ("Arquivo:/"+"D:/" D:/SRC "/SR; // Classe de carregamento e URLClassLoader Ul = novo URLClassLoader (URLs); Classe C = ul.loadclass ("test.serviceImpl2"); // Retorna o construtor público especificado da classe representado pelo objeto de classe. Construtor ctr = c.getConstructor (InvocationHandle.class); // usa o método do construtor representado por esse objeto construtor CTR para criar uma nova instância da classe de declaração do método do construtor e inicializar a instância com o objeto de parâmetro de inicialização especificado m = ctr.newInstance (h); retornar m; }}5. Resumo 1. O chamado proxy dinâmico é uma classe. É uma classe gerada em tempo de execução. Ao gerá -lo, você deve fornecer um conjunto de interfaces e alterar a classe para afirmar que ela implementa essas interfaces. No entanto, ele não fará um trabalho substancial para você, mas assumirá o trabalho real com base no manipulador de parâmetros (ou seja, a classe de implementação da interface InvocationHandler) fornecida quando você gerar a instância.
2. O design do proxy faz com que ele suporta apenas o proxy da interface. O mecanismo de herança de Java destinou que a classe de proxy dinâmica não pode implementar proxy dinâmico para a classe, porque a herança múltipla não é essencialmente viável em Java.
O exposto acima é tudo sobre este artigo, espero que seja útil para o aprendizado de todos.