Atenção: esse artigo tem um vídeo complementar. Clique e assista!

De que se trata o artigo:

Este artigo apresenta ao leitor as funcionalidades de interceptadores, decoradores, eventos e estereótipos, da maneira como são implementadas em Weld. Interceptadores, decoradores e eventos facilitam a tarefa de criar aplicações mais modulares e permitem complementar o comportamento de beans de forma transparente. Estereótipos, por sua vez, dão ao programador a possibilidade de definir várias características de beans de maneira reaproveitável e clara.


Em que situação o tema é útil:

As funcionalidades apresentadas neste artigo são usadas em vários módulos que compõem o Seam 3. Compreendê-las é imprescindível para entender como certas funcionalidades do Seam 3 são implementadas, e como utilizar estas funcionalidades. Deste modo, o estudo de interceptadores, decoradores, eventos e estereótipos é crucial para a compreensão do Seam 3.

Resumo DevMan:

JBoss Seam 3 é um dos mais recentes e modernos frameworks disponíveis para o desenvolvedor web Java. Seu poder, modularidade e flexibilidade derivam de uma das mais novas e poderosas especificações de Java EE 6, CDI, e da implementação mais popular desta tecnologia, Weld. No artigo anterior desta série, vimos os princípios básicos de CDI e Weld; neste artigo, estudaremos as poderosas (e seguras) ferramentas para interceptação, decoração, comunicação por eventos e padronização de beans.

Conforme vimos no artigo anterior, Seam 3, o novo framework da JBoss, é baseado na especificação CDI e roda sobre sua implementação de referência, o Weld. Uma das principais funcionalidades providas pelo Weld é a injeção de dependências. Através dela, CDI fornece uma maneira nativa de se desacoplar componentes, e seu modelo de injeção de dependências usa o poder do sistema de tipos de Java para injetar beans de maneira flexível e, principalmente, segura.

Ademais, Weld também permite o gerenciamento do ciclo de vida de beans baseado em escopos. Os contextos de CDI, semelhantes aos utilizados em JSF 2, são uma opção nativa e formalmente especificada para o gerenciamento do escopo de beans. Em conjunto com a possibilidade de atribuir nomes EL a beans, estas funcionalidades tornam Weld uma opção bastante atrativa para o desenvolvedor da plataforma Java, especialmente aquele que utiliza JSF.

Entretanto, estas não são as únicas necessidades tradicionais do desenvolvimento web que CDI veio satisfazer. Desenvolvedores Java EE, por exemplo, têm a constante necessidade de executar certa lógica para complementar o comportamento de código já escrito – e é possível fazer isto com Weld através de interceptadores, decoradores e eventos. Outras vezes, é preciso atribuir um “rótulo” a um conjunto de beans, de modo que os beans “rotulados” possam ser tratados de maneira diferente. Isto pode ser feito através dos estereótipos.

O conhecimento de tais funcionalidades, além de útil por si só, facilitará nossa compreensão de como o Seam 3 é funcional. Deste modo, neste artigo, veremos cada uma destas facilidades, começando por interceptadores.

Interceptadores

Às vezes, precisamos que determinada atividade seja executada sempre em uma determinada situação. É preciso confirmar (ou reverter) alterações quando um código transacional se encerra, registrar nos logs que determinado método foi executado, liberar recursos de um objeto quando ele for destruído, etc. Estas atividades geralmente transcendem a lógica de negócio da aplicação, podendo ser necessárias em vários pontos do software.

A plataforma Java EE utiliza o conceito de interceptadores (ou interceptors) para facilitar este trabalho. Um interceptador é uma classe que captura a linha de execução de uma thread quando um método – o método interceptado – for invocado. Um interceptador pode executar uma ação antes ou depois da execução do método interceptado, ou mesmo impedir que o método interceptado seja, de fato, invocado. É possível interceptar as mais diversas classes e métodos com um interceptador. EJBs, por exemplo, já podiam ser interceptados, mas a maneira de fazê-lo era um tanto problemática, por várias razões.

Interceptor bindings

A JSR-299, felizmente, simplificou bastante o uso de interceptadores. Em CDI, um interceptador é ligado a uma classe ou método através de uma anotação especial, chamada ligador de interceptação, ou interceptor binding. Cada interceptador possui seu próprio interceptor binding. Assim, digamos que queremos registrar no log do servidor a invocação de certos métodos. Para isto, anotaríamos o método (ou mesmo uma classe inteira) com um interceptor binding. Se nosso interceptor binding se chamar @LogarInvocacaoDeMetodos, ele seria aplicado como abaixo:


  @LogarInvocacaoDeMetodos
  public class MeuBean {
      public String getNome() {
          return "nome";
      }
  } 

Como anotações em geral, é fácil declarar um interceptor binding. Para ver como isto é feito, criemos o interceptor binding @LogarInvocacaoDeMetodos. Para declarar que uma anotação é um interceptor binding, a marcamos com a meta-anotação @InterceptorBinding.


  @InterceptorBinding 

Outra característica de interceptor bindings é terem como alvo, geralmente, tanto classes quanto métodos. Um interceptor binding deve necessariamente ter classes como alvo, porque o interceptador (isto é, o bean que efetivamente executará ações ao capturar métodos) deve ser anotado com o interceptor binding. Ademais, como frequentemente é necessário anotar apenas alguns métodos de um bean, interceptor bindings geralmente também têm métodos como alvo:


  @Target({ElementType.METHOD, ElementType.TYPE}) 

Por fim, uma vez que ligações de interceptadores devem estar disponíveis para consulta enquanto a aplicação roda, a anotação deve ser mantida em tempo de execução:


  @Retention(RetentionPolicy.RUNTIME) 

Feito isto, declaramos nossa interface. O código completo, incluindo a última linha abaixo, pode ser visto na Listagem 1.


  public @interface LogarInvocacaoDeMetodos {} 

Listagem 1. A anotação @LogarInvocacaoDeMetodos: exemplo de interceptor binding.


  @InterceptorBinding
  @Target({ElementType.METHOD, ElementType.TYPE})
  @Retention(RetentionPolicy.RUNTIME)
  public @interface LogarInvocacaoDeMetodos {}  ... 

Quer ler esse conteúdo completo? Tenha acesso completo