SeamFramework.orgCommunity Documentation
Até agora, vimos alguns exemplos de anotações de tipo de escopo. O escopo de um Web Bean determina o ciclo de vida das instâncias do Web Bean. O escopo também determina que clientes se referem a quais instâncias do Web Bean. De acordo com a especificação Web Beans, um escopo determina:
Quando uma nova instância de qualquer Web Bean com esse escopo é criada
Quando uma instância de qualquer Web Bean com esse escopo é destruída
Cada referência injetada refere-se a qualquer instância de um Web Bean com esse escopo
Por exemplo, se temos um Web Bean de escopo de sessão CurrentUser
, todos os Web Beans que são chamados no contexto dele HttpSession
verão a mesma instância do CurrentUser
. Essa instância será criada automaticamente na primeira vez que um CurrentUser
for necessário nessa sessão, e será automaticamente destruída quando a sessão terminar.
Web Beans possui um modelo extensível de contexto. É possível definir novos escopos, criando uma nova anotação de tipo de escopo:
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}
Evidentemente, essa é a parte mais fácil do trabalho. Para esse tipo de escopo ser útil, nós também precisamos definir um objeto Context
que implementa o escopo! Implementar um Context
é geralmente uma tarefa muito técnica, destinada apenas ao desenvolvimento do framework.
Podemos aplicar uma anotação de tipo de escopo a uma classe de implementação de um Web Bean para especificar o escopo do Web Bean:
@ClusterScoped
public class SecondLevelCache { ... }
Normalmente, você usará um dos escopos pré-definidos na Web Bean.
A Web Beans pré-define quatro tipos de escopos:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
Para uma aplicação web que utiliza Web Beans:
qualquer requisição servlet tem acesso aos escopos de requisição, sessão e aplicação ativos, e, adicionalmente
qualquer requisição JSF tem acesso ao escopo de conversação ativo.
Os escopos de request e aplicação também estão disponíveis:
durante invocações de métodos remotos de EJB,
durante timeouts de EJB,
durante a entrega de uma mensagem a um mensagem-driven bean, e
durante a invocação de um web service
Se a aplicação tentar invocar um Web Bean com um escopo que não tem um contexto ativo, uma ContextNotActiveException
é lançada pelo gerenciador do Web Bean em tempo de execução.
Três dos quatro escopos pré-definidos devem ser extremamente familiares a todos os desenvolvedores Java EE, então não vamos perder tempo discutindo-os aqui. Um dos escopos, porém, é novo.
O escopo de conversação da Web Beans é um parecido com o tradicional escopo de sessão na medida em que mantém estado associado a um usuário do sistema, e o mantém durante várias requisições para o servidor. No entanto, ao contrário do escopo de sessão, o escopo de conversação:
é demarcado explicitamente pela aplicação, e
mantém o estado associado a uma determinada aba em um navegador web em uma aplicação JSF.
Uma conversação representa uma tarefa, uma unidade de trabalho do ponto-de-vista do usuário. O contexto de conversação mantém o estado associado ao usuário que estiver utilizando no momento. Se o usuário estiver fazendo várias coisas ao mesmo tempo, existem várias conversações.
A conversação está ativa durante qualquer requisição JSF. No entanto, a maioria das coversações é destruída no final da requisição. Se uma conversação deve manter estado através de múltiplas requisições, deve explicitamente ser promovida para uma conversação de longa duração (long-running conversation).
Web Beans oferece um Web Bean pré-definido para o controle do ciclo de vida das conversações em uma aplicação JSF. Esse Web Bean pode ser obtido por injeção:
@Current Conversation conversation;
Para promover a conversação associada a requisição atual em uma conversação de longa duração, chame o método begin()
no código da aplicação. Para agendar a destruição do atual contexto de conversão de longa duração no final da requisição atual, chame end()
.
No exemplo a seguir, um Web Bean em escopo de conversação controla a conversação ao qual estiver associado:
@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Current Conversation conversation;
private @PersistenceContext(type=EXTENDED) EntityManager em;
@Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add( new LineItem(product, quantity) );
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
@Remove
public void destroy() {}
}
Esse Web Bean é capaz de controlar seu próprio ciclo de vida através do uso da API Conversation
. Mas alguns outros Web Beans têm um cliclo vida que depende totalmente de um outro objeto.
Contexto de conversação propaga-se automaticamente em qualquer requisição faces JSF (formulário de submissão JSF). E não se propaga automaticamente em requisições não-faces, por exemplo, em navegação através de um link.
Nós podemos forçar a propagação da conversação em uma requisição não-faces incluindo o identificador único da conversação como um parâmetro da requisição. A especificação Web Beans reserva o parâmetro denominado cid
para essa utilização. O identificador único da conversação pode ser obtido a partir do objeto Conversation
, que tem o nome Web Bean conversation
.
Portanto, o seguinte link propaga a conversação:
<a href="/addProduct.jsp?cid=#{conversation.id}" >Add Product</a >
O gerenciador do Web Bean também é utilizado para propagar conversações em qualquer redirecionamento, mesmo se a conversação não estiver marcada como uma conversação de longa duração. Isso torna muito fácil a implementação do padrão POST-then-redirect, sem ter de recorrer a construções frágeis, como um objeto "flash". Neste caso, o gerenciador do Web Bean automaticamente adiciona um parâmetro de requisição a URL redirecionada.
O gerenciador do Web Bean pode destruir uma conversação e todos os estados mantidos em seu contexto, a qualquer momento, a fim de preservar recursos. A implementação do gerenciador do Web Bean irá normalmente fazer isso, com base em algum tipo de timeout embora isso não seja exigido pela especificação Web Beans. O timeout é o período de inatividade antes que a conversação seja destruída.
O objeto Conversation
fornece um método para definir o tempo limite (timeout). Essa é uma sugestão para o gerente do Web Bean, que é livre para ignorar essa configuração.
conversation.setTimeout(timeoutInMillis);
Além dos quatro escopos pré-definidos, Web Beans possui o chamado dependent pseudo-scope. Esse é o escopo padrão para um Web Bean que não declare explicitamente um tipo de escopo.
Por exemplo, esse Web Bean tem o tipo de escopo @Dependent
:
public class Calculator { ... }
Quando um ponto de injeção num Web Bean resolve para um Web Bean dependente, uma nova instância do Web Bean dependente é criada a cada vez que o primeiro Web Bean for instanciado. Instâncias de Web Beans dependentes nunca são compartilhadas entre diferentes Web Beans ou diferentes pontos de injeção. Eles são objetos dependentes de alguma outra instância de Web Bean.
Instâncias de Web Bean dependentes são destruídas quando a instância de que eles dependem é destruída.
Web Beans torna fácil a obtenção de uma instância dependente de uma classe Java ou um EJB, mesmo se a classe ou EJB já tiverem sido declarados como um Web Bean com outro tipo de escopo.
A anotação de binding pré-definida @New
permite a definição implicita de um Web Bean dependente em um ponto de injeção. Suponha que nós declaramos o seguinte campo injetado:
@New Calculator calculator;
Em seguida, um Web Bean com escopo @Dependent
, tipo de binding @New
, API do tipo Calculator
, classe de implementação Calculator
e tipo de implantação @Standard
é definido implicitamente.
Isso é verdade mesmo se Calculator
já estiver declarado com um tipo de escopo diferente, por exemplo:
@ConversationScoped
public class Calculator { ... }
Portanto, os seguintes atributos injetados obtêm uma instância diferente de Calculator
:
public class PaymentCalc {
@Current Calculator calculator;
@New Calculator newCalculator;
}
O campo calculator
tem uma instância de Calculator
em escopo de conversação injetada. O campo newCalculator
tem uma nova instância do Calculator
injetada, com ciclo de vida que é vinculado à PaymentCalc
.
Essa funcionalidade é particularmente útil em métodos produtores, como poderemos verificar no próximo capítulo.