Aplicação prática do Padrão Proxy

A ideia do padrão Proxy é simples,  dado um objeto do nosso sistema com um método foo, ao realizar uma chamada pojo.foo(), o método foo do POJO é acessado diretamente

Para aplicar o padrão precisamos inserir um objeto intermediário, que será do mesmo tipo do objeto pojo – implementando as mesmas interfaces ou herdando da mesma classe do pojo – que irá receber todas as chamadas aos métodos e realizar as devidas verificações e processamentos.

Para criar este objeto intermediário, devemos implementar uma classe com a devida equivalência de tipos ou, podemos criar dinamicamente uma classe que implemente as devidas interfaces/super classe.

Aplicação Prática do Proxy

Na linguagem Java,  é possível criar os chamados proxies dinâmicos por meio da API de Proxy. Porém, esta forma apresenta algumas restrições, pois permite apenas a criação de Proxy de interfaces. Ou seja, nossos objetos devem obrigatoriamente implementar uma interface comum  (Que é criada dinamicamente pelas interfaces informadas em tempo de execução).

Um cenário onde o padrão é aplicado é em um Pool de Conexões.  Ao obter uma conexão de uma fonte de dados (java.sql.DataSurce), a aplicação realiza suas leituras/escritas no banco de dados e, quando não é mais necessária,  fecha a conexão pela chamada ao método close da interface java.sql.Connection. A imagem abaixo apresenta o ciclo de vida de uma conexão em um pool.

Sendo assim, para controlar esta devolução da conexão ao pool, e não fechar a conexão de fato, é possível utilizar o padrão proxy. O exemplo de código apresentado a seguir é baseado no projeto flexy-pool.

A linha 0 1-6 temos a criação do Proxy dinâmico por meio do método estático java.lang.reflect.Proxy#newProxyInstance. O primeiro argumento é o classloader onde o proxy criado será carregado, normalmente é passado o mesmo classloader do objeto this. Já o segundo, é a lista de interfaces que serão implementadas dinamicamente pela instância do proxy. Estas interfaces  definem a tipagem do objeto criado, ou seja,  quais métodos serão possíveis invocar e, quais tipos ele pode ser atribuído. Em nosso exemplo, a interface javax.sql.Connection.

O último parâmetro é uma instância da interface InvocationHandler, implementada pela classe ConnectionInvocationHandler em nosso exemplo. Cada instância de Proxy deve possuir um Invocation Handler associado. Quando qualquer método é chamado em uma instância do Proxy,  a chamada é encaminhada para o método invoke do Invocation Handler, que recebe informações de qual método do foi chamado e quais foram os parâmetros fornecidos. Com o uso desta classe, podemos intermediar a comunicação com o objeto encapsulado.

A implementação do método apresentado faz com que, quando um método close for chamado pela aplicação, a conexão seja devolvida ao pool. A lógica que implementa este algoritmo é delegada para uma instância de ConnectionCallback, uma interface própria do flexy-pool. Quando qualquer outro método da interface Connection for invocado, o invocation handler irá delegar a chamada para o objeto encapsulado, que ocorre  na linha 23, via API de reflexão.

Considerações finais

É possível aplicar proxies em muitos outros cenários, para citar algumas aplicações reais, temos o módulo spring-aop, do Spring framework, que utiliza como base para criação dos Aspectos. Um exemplo bacana do uso de proxies no Spring framework é utilizado pelo projeto Spring Data para transformar nossas interfaces de Repositório – “magicamente” – em algo funcional. Por falar em “data”, o Hibernate utiliza para implementar a recuperação de informações Lazy-loading. Outro exemplo é encontrado nos frameworks de testes, tais como Mockito, utilizam proxies para criação de objetos Mocks.

Por fim, caso seja desejado criar proxies de classes, podemos fazê-lo utilizando bibliotecas de terceiros, como a cglib, javassist e byte buddy que são responsáveis por outras atividades além da criação de proxies, em especial, manipulação de bytecode.

 

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s