Spring em Seam, Parte 2: Quando há colisão entre stateless e stateful – Etapa 02

por:
Dan Allen


Spring, conheça estado

Se existe uma coisa que você notou o primeiro artigo desta série, é que a criação de um componente híbrido Spring-Seam significou digitar a tag <seam:component> várias vezes. Isso é um tipo de regressão na forma de desenvolver, pois o objetivo do Seam é reduzir digitação, e esta tag está apenas contribuindo para a confusa pilha de XML no Spring. Felizmente, existe uma forma mais simples de atingir o mesmo objetivo que destaca uma outra funcionalidade altamente antecipada do Spring 2.0: escopo personalizado. Escopos personalizados expandem as escolhas para onde as instâncias de beans Spring podem ser armazenadas.

Enquanto Spring adicionou o mecanismo para apoiar escopos personalizados, as implementações embutidas no framework estão presas no passado, somente cobrindo os escopos na API do Servlet (request, session e application), além de um escopo stateless chamado prototype. Esses escopos não são tão bem adequados para as aplicações comerciais modernas. Para trazer o Spring ao momento atual, Seam registra um manipulador de escopo personalizado que permite que os beans Spring sejam armazenados no contexto do Seam. Usos incluem o escopo de conversação (temporário) para implementar o padrão redirect-after-post (algumas vezes chamados de flash); o escopo de conversação de longa execução (long-running) para fluxos de páginas de usuário simples; e o escopo de processo de negócio para apoiar interações a partir de múltiplos usuários sobre um período prolongado de tempo. Ao menos, beans Spring podem ser stateful sem ter que recorrer ao apoio da sessão HTTP!

Como se constata, especificar um escopo Seam em um bean Spring possui o mesmo efeito de aplicar uma tag <seam:component> para a definição do bean no qual resulta em um componente híbrido Spring-Seam. Um acordo dois-para-um! Para tirar vantagem desta funcionalidade, você primeiro precisa registrar o manipulador de escopo Seam em qualquer um dos arquivos de configuração do Spring (mas não mais que uma vez) usando a tag apresentada na Listagem 1. Este arquivo de configuração deve também declarar o namespace Seam namespace no elemento raiz, que foi explicado no primeiro artigo desta série.

Listagem 1. Registrando o manipulador de escopo Seam no Spring

<seam:configure-scopes/>

Para associar um escopo Seam a um bean Spring, criando dessa forma um componente híbrido Spring-Seam, você simplesmente configure o atributo scope (escopo) a definição de um <bean> Spring – ou qualquer elemento namespace personalizado na configuração do Spring que suporte o atributo scope – para um dos escopos Seam. O nome do escopo não é case-sensitive (ele não vê diferença entre letras maiúsculas e minúsculas).

Para distinguir os escopos Seam dos escopos providos por outros frameworks, o nome do escopo é prefixado com um namespace, que, por padrão, é seam. Para colocar todos os escopos juntos, você cria um componente com o escopo de conversação através do uso do valor seam.CONVERSATION no atributo scope. Você pode customizar o prefixo usado no namespace através da sobreposição do atributo prefix da declaração <seam:configure-scopes>, como mostra a Listagem 2.

 

Listagem 2. Sobrepondo o prefixo padrão para o namespace de um escopo

<seam:configure-scopes prefix="org.jboss.seam.ScopeType"/>


Neste caso, o valor do atributo scope se tornaria org.jboss.seam.ScopeType.CONVERSATION, que passaria a ser um nome completamente qualificado da constante enum para o escopo de conversação.

Na primeira parte desta série, fomos apresentados a uma aplicação que é usada para gerenciar um banco de dados de torneios de golfe que está disponível aos clientes através de um Web service. As operações de leitura e escrita para a entidade Torneio (Tournament) são tratadas pelo bean tournamentManager, um clássico singleton bean Spring (descrito com detalhes no primeiro artigo). Ele não é muito interessante em nossa busca por estados. No entanto, uma das belezas da tentativa de integrar Spring e Seam é que beans Spring stateless, tais como o bean tournamentManager, pode ser infundido com estado através do uso de outro bean stateful. Para ver como isso é feito, vamos iniciar a criação de um bean de critérios de busca que é armazenado no escopo de conversação do Seam. A definição deste bean está descrita na Listagem 3. Por enquanto, estamos respeitando o prefixo de namespace padrão para o nome do escopo.
 

Listagem 3. Definição de um bean Spring stateful


<bean id="tournamentSearchCriteria" class="org.open18.partner.business.TournamentSearchCriteria"

  scope="seam.CONVERSATION"/>


Quando estamos trabalhando com o contexto de conversação de longa execução (long-running) no Seam, o bean tournamentSearchCriteria é instanciado uma vez, no primeiro momento em que ele é usado, e se mantém disponível enquanto a conversação durar. Manter este bean no escopo é importante para que os critérios de busca digitados pelo usuário não sejam perdidos entre requisições. Existem várias formas de iniciar uma conversação de longa duração no Seam. Como o tournamentManager já está em um componente híbrido Spring-Seam, a forma mais simples para se obter isso pode ser adicionar uma anotação @Begin(join = true) do Seam  para o método de busca.

Quando você declara componentes híbridos Spring-Seam usando o atributo scope, você perde alguma flexibilidade sobre a configuração do componente. Enquanto a configuração do escopo estiver ativa, o que está desativado é a habilidade de configurar a flag auto-create, prover uma classe explícita, fornecer um nome de variável personalizado e desabilitar interceptores Seam. Felizmente, existem outras formas de configurar algumas dessas configurações, que será visto a seguir. Mas lembre que a idéia aqui é usar a tag <bean> sem qualquer interferência adicional, ao lado do valor do atributo scope. Esta abordagem é apenas um atalho para a declaração mais formal <seam:component>, que nos dá um poder extra em caso de precisarmos dele, incluindo a habilidade de especificar o escopo Seam.

A flag auto-create é configurada para falso por padrão para componentes configurados usando o atributo scope. No entanto, esta configuração pode ser controlada globalmente usando o atributo default-auto-create na tag <seam:configure-scopes>, como exibido na Listagem 4. Durante este artigo, iremos assumir o uso desta configuração na qual o Spring inicializa o bean para o Seam quando ele for requisitado.

 

Listagem 4. Configurando a flag auto-create globalmente

<seam:configure-scopes default-auto-create="true"/>


A Listagem 5 ilustra a único forma de desabilitar interceptor configurando usando o atributo scope: através da adição da anotação @BypassInterceptors do Seam na classe.

 

Listagem 5. Disabilitando interceptores em um componente híbrido Spring-Seam

@BypassInterceptors

public class TournamentManagerImpl implements TournamentManager {

    ...

}


Agora que temos nosso escopo Seam do bean Spring definido, queremos iniciar o seu uso em outros beans.