Spring com Seam, Parte 1: Contruindo um Componente Híbrido Spring-Seam – Etapa 02
Componente híbrido Spring-Seam
Existe uma certa quantidade de comportamento “mágico” que o Spring adiciona aos seus beans na forma de BeanPostProcessors. Se você registra uma classe do framework Spring que depende de uma funcionalidade provida diretamente por um componente Seam, você carrega a tarefa de emular o trabalho feito pelo container Spring. Seria melhor deixar o Spring fazer seu trabalho necessário e então acessar o Seam e consumir o produto final.
Isso descreve perfeitamente o comportamento de um componente híbrido Spring-Seam. Seam provê uma tag XML que é usada em uma definição de um bean Spring para indicar então ao bean Spring que ele pode ser tratado como um componente Seam de primeira classe. Assim como outros componentes Seam, o componente híbrido é, dado um nome, registrado no container Seam e envolvido com interceptores Seam quando instanciado. Vamos ver agora como Seam permite que você entrelace esta funcionalidade na definição de um bean Spring.
Preparando o Spring
Para iniciar a criação de um componente híbrido Spring-Seam, existem dois requisitos que sua aplicação deve atender. Você deve primeiramente incluir a biblioteca de integração de IoC do Seam, jboss-seam-ioc.jar, em seu classpath. Em seguida, como ilustrado na Listagem 5, você deve registrar o namespace do XML do Seam no arquivo de configuração do Spring para usar tags customizadas a partir do namespace do Seam (ex:
Listagem 5. Registrando o namespace do XML do Seam
As tags customizadas no namespace do seam fazem mais que simplesmente reduzir keystrokes e prover validação implícita dos nomes das propriedades. O atributo chave do uso de tags customizadas no arquivo de configuração do Spring é o ganho de criação de bean capturado por uma implementação da classe NamespaceHandler do Spring. Esta implementação é destinada a um prefixo particular de um namespace de XML. A classe NamespaceHandler transforma os elementos XML que ela reconhece para produzir um bean Spring, decorar um bean existente ou registrar funcionalidade no container Spring.
Seam fornece uma implementação da classe NamespaceHandler para processar tags no arquivo de configuração do Spring que usa o namespace do Seam. Uma certa tag,
Um ponto importante para se lembrar: se você não estiver usando Seam para inicializar o Spring e você planeja usar componentes híbridos Spring-Seam, você deve estar certo de que a declaração SeamListener aparece antes da declaração ContextLoaderListener no descritor web.xml. Esta ordenação é necessária porque o container Seam está ativo e pronto para tratar os retornos vindos de sua classe customizada NamespaceHandler quando o arquivo de configuração do Spring é processado. No entanto, você pode ainda encontrar outros problemas não relacionados durante a inicialização. Portanto, é recomendado fortemente usar Seam para inicializar o container Spring.
Vamos ver agora como incorporar a tag
Incorporando a tag
Seam é capaz de decorar um bean Spring como um componente Seam através da inclusão de uma tag
A definição do bean Spring tournamentManager está apresentada na Listagem 6. Este bean atua como a interface de negócio para gerenciar uma coleção de torneios de golf. Os dados do torneio de golf é mantido por um partner (cujo nome do pacote é org.open18.parter) e exposto para a aplicação Open 18, um portal de comunidade de golf, através de um Web service. O foco da aplicação Web de exemplo usado neste artigo será direcionado ao gerenciamento por trás (back-end) dos dados do torneio. Note que o bean tournamentManager foi promovido para um componente Seam através do uso da tag
Listando 6. Definindo um componente híbrido Spring-Seam
Seam deriva a variável de contexto name usada para referenciar o componente Seam a partir do identificador do bean Spring, que pode ser fornecido como a ID ou o atributo name do elemento
Listando 7. Providing an alternate Seam component name
Por padrão, o componente Seam tem seu escopo associado ao contexto ScopeType.STATELESS. O contexto stateless é selecionado como o escopo padrão do Seam porque, na maioria das vezes, o bean Spring é um singleton (ver Nota 1). Assim, não existe benefício em armazenar o bean em um escopo real do Seam, pois ele já estará iniciado durante todo o ciclo de vida do container. O contexto stateless é também usado para deixar o Spring gerenciar o escopo do bean, se o bean não for um singleton. O Spring agora suporta escopos customizados, tais como o escopo de fluxo a partir do Fluxo Web do Spring. O uso do contexto stateless previne o Seam de interferências com o plano do Spring para o bean e evita o caso onde Seam está usando uma referência ultrapassada para um bean.
Nota 1. Singleton
Singleton é um padrão de projeto de software (do inglês Design Pattern). Este padrão garante a existência de apenas uma instância de uma classe, mantendo um ponto global de acesso ao seu objeto.
Muitos projetos necessitam que algumas classes tenham apenas uma instância. Por exemplo, em uma aplicação que precisa de uma infra-estrutura de log de dados, pode-se implementar uma classe no padrão singleton. Desta forma, existe apenas um objeto responsável pelo log em toda a aplicação que é acessível unicamente através da classe singleton.
Segue um exemplo em Java de classe Singleton usada em log de dados. Esta classe suporta inicialização sob demanda e ambientes multi-thread.
public class SingletonLog {
// Construtor privado. Suprime o construtor publico padrão.
private SingletonLog() {
// Leitura da configuração de log. Normalmente descrita em um arquivo.
}
// Faz o log de eventos da aplicação
public void doLog(String eventDescription) {
}
//Retorna a instancia única da classe SingletonLog
public static SingletonLog getInstance() {
return SingletonLogHolder.instance;
}
//Classe auxiliar para criação da instancia. Evita problemas de sincronização de threads.
private static class SingletonLogHolder {
private static SingletonLog instance = new SingletonLog();
}
}
Tenha em mente, mesmo assim, que a partir do uso do contexto stateless, Seam irá requisitar o bean a partir do container Seam toda vez que a variável de contexto correspondente é resolvida. Este mesmo lookup recorrente ocorreria se o bean Spring fosse acessado através de uma ponte do RLE. Você não precisa se preocupar em adicionar overhead a menos que o bean Spring seja um protótipo, onde neste caso você deve saber que o bean será instanciado em cada lookup.
Se você pretende fazer o bean Spring stateful (o posto de singleton), é melhor tê-lo armazenado em um escopo Seam. O escopo Seam é apoiado usando o atributo scope na tag
Para demonstrar esta capacidade, vamos definir um bean de critérios de busca, exibido na Listagem 8, que é usado em conjunção com o bean tournamentManager para filtrar a coleção de torneios que são exibidos na interface do usuário. A escolha do escopo de conversação assegura que o critério de busca é carregado em memória pelo período da interação do usuário com o formulário de busca.
Listagem 8. Um bean Spring de escopo de conversação
aloca uma nova instância. Mas, apesar do bean resolvido ser armazenado em uma variável de
contexto de escopo de conversação neste caso, Seam somente pede ao Spring para criar
uma instância uma vez por conversação do usuário. É um casamento ideal da funcionalidade
de cada container. No próximo artigo, você aprenderá sobre outra forma de definer o escopo
de um bean Spring para um contexto do Seam usando mecanismo de definição do escopo do
Spring, e você irá também estudar os perigos da impedância do escopo.