Como escolher o escopo de bean certo?

Respostas:

485

Introdução

Representa o escopo (a vida útil) do bean. Isso é mais fácil de entender se você estiver familiarizado com o trabalho "oculto" de um aplicativo da web de servlet básico: Como os servlets funcionam? Instanciação, sessões, variáveis ​​compartilhadas e multithreading .


@Request/View/Flow/Session/ApplicationScoped

Um @RequestScopedbean dura o tempo que um único ciclo de solicitação-resposta HTTP (observe que uma solicitação Ajax também conta como uma única solicitação HTTP). Um @ViewScopedbean permanece enquanto você está interagindo com a mesma visualização JSF por postbacks que chamam métodos de ação retornando null/ voidsem nenhuma navegação / redirecionamento. Um @FlowScopedbean dura enquanto você estiver navegando pela coleção especificada de visualizações registradas no arquivo de configuração do fluxo. Um @SessionScopedbean permanece enquanto a sessão HTTP estabelecida. Um @ApplicationScopedbean dura enquanto o aplicativo da web é executado. Observe que o CDI @Modelé basicamente um estereótipo para @Named @RequestScoped, então as mesmas regras se aplicam.

Qual escopo escolher depende apenas dos dados (o estado) que o bean mantém e representa. Use @RequestScopedpara formulários / apresentações simples e não-ajax. Use @ViewScopedpara visualizações dinâmicas ativadas por ajax (validação, renderização, caixas de diálogo, etc.). Use @FlowScopedpara o padrão "assistente" ("questionário") de coleta de dados de entrada espalhados por várias páginas. Use @SessionScopedpara dados específicos do cliente, como usuário conectado e preferências do usuário (idioma etc.). Use @ApplicationScopedpara dados / constantes abrangentes do aplicativo, como listas suspensas iguais para todos, ou beans gerenciados sem nenhuma variável de instância e possuindo apenas métodos.

O abuso de um @ApplicationScopedbean para dados com escopo de sessão / exibição / solicitação faria com que ele fosse compartilhado entre todos os usuários, para que qualquer pessoa possa ver os dados um do outro, o que está errado. O abuso de um @SessionScopedbean para dados com escopo de exibição / solicitação faria com que fosse compartilhado entre todas as guias / janelas em uma única sessão do navegador, para que o usuário final possa experimentar inconsistências ao interagir com todas as visualizações após alternar entre guias, o que é ruim para a experiência do usuário. O abuso de um @RequestScopedbean para dados com escopo de exibição faria com que os dados com escopo fossem reinicializados para o padrão em cada postagem (ajax), causando possivelmente formulários que não funcionam ( veja também os pontos 4 e 5 aqui ). Abusar de um @ViewScopedbean para dados com escopo de solicitação, sessão ou aplicativo e abusar de um@SessionScoped O bean para dados com escopo do aplicativo não afeta o cliente, mas ocupa desnecessariamente a memória do servidor e é ineficiente.

Observe que o escopo não deve ser escolhido com base nas implicações de desempenho, a menos que você realmente tenha pouco espaço na memória e queira ficar completamente sem estado; você precisaria usar exclusivamente @RequestScopedbeans e mexer com parâmetros de solicitação para manter o estado do cliente. Observe também que quando você tem uma única página JSF com dados com escopo diferente, é perfeitamente válido colocá-los em beans de backup separados em um escopo que corresponda ao escopo dos dados. Os beans podem apenas acessar um ao outro via @ManagedPropertyno caso de beans gerenciados JSF ou @Injectno caso de beans gerenciados CDI.

Veja também:


@CustomScoped/NoneScoped/Dependent

Isso não é mencionado na sua pergunta, mas o JSF (legado) também suporta @CustomScopede @NoneScoped, que raramente são usados ​​no mundo real. Ele @CustomScopeddeve se referir a uma Map<K, Bean>implementação customizada em um escopo mais amplo que foi substituído Map#put()e / ou Map#get()para ter um controle mais refinado da criação e / ou destruição do bean.

O JSF @NoneScopede o CDI @Dependentvivem basicamente enquanto uma única avaliação EL no bean. Imagine um formulário de login com dois campos de entrada referentes a uma propriedade de bean e um botão de comando referente a uma ação de bean, portanto, com um total de três expressões EL, e efetivamente três instâncias serão criadas. Um com o nome de usuário definido, um com a senha definida e um no qual a ação é invocada. Você normalmente deseja usar esse escopo apenas em beans que devem permanecer enquanto o bean estiver sendo injetado. Portanto, se um @NoneScopedou @Dependentfor injetado em um @SessionScoped, ele viverá tanto quanto o @SessionScopedfeijão.

Veja também:


Escopo Flash

Por último, o JSF também suporta o escopo do flash. É apoiado por um cookie de curta duração, associado a uma entrada de dados no escopo da sessão. Antes do redirecionamento, um cookie será definido na resposta HTTP com um valor associado exclusivamente à entrada de dados no escopo da sessão. Após o redirecionamento, a presença do cookie do escopo flash será verificada e a entrada de dados associada ao cookie será removida do escopo da sessão e colocada no escopo da solicitação redirecionada. Finalmente, o cookie será removido da resposta HTTP. Dessa forma, a solicitação redirecionada tem acesso aos dados com escopo definido, que foram preparados na solicitação inicial.

Na verdade, isso não está disponível como um escopo de bean gerenciado, ou seja, não existe @FlashScoped. O escopo do flash está disponível apenas como um mapa ExternalContext#getFlash()nos beans gerenciados e #{flash}no EL.

Veja também:

BalusC
fonte
4
Eu acho que uma referência à sua resposta à pergunta " Como e quando um bean de escopo de exibição é destruído no JSF? " É relevante aqui.
Lii 20/01
3
@ Cold: esse é um escopo CDI antigo e no JSF 2.2 substituído por @FlowScoped(não é necessário iniciar / parar manualmente).
precisa saber é o seguinte
11
E a DeltaSpike também tem ViewAccesscopedeWindowScoped
Kukeltje
@ BalusC, acho que há um problema, com o ViewScopedbean no MyFaces 2.2. Atualmente, estou enfrentando um problema com o ViewScopedbean e o Ajax, que publiquei aqui . No MyFaces JIRA, também há uma discussão sobre esse tópico.
Tapas Bose
O CDI define quatro escopos internos: @RequestScoped @SessionScoped @ApplicationScoped @ConversationScoped por que os escopos que você descreve são diferentes?
Hosein Aqajani
122

Desde o JSF 2.3, todos os escopos de bean definidos no pacote javax.faces.beanpackage foram descontinuados para alinhar os escopos ao CDI. Além disso, eles são aplicáveis ​​apenas se seu bean estiver usando @ManagedBeananotação. Se você estiver usando as versões JSF abaixo de 2.3, consulte a resposta herdada no final.


No JSF 2.3, aqui estão os escopos que podem ser usados ​​no JSF Backing Beans:

1@javax.enterprise.context.ApplicationScoped .: O escopo do aplicativo persiste por toda a duração do aplicativo da web. Esse escopo é compartilhado entre todas as solicitações e todas as sessões. Isso é útil quando você possui dados para todo o aplicativo.

2@javax.enterprise.context.SessionScoped .: O escopo da sessão persiste desde o momento em que uma sessão é estabelecida até o término da sessão. O contexto da sessão é compartilhado entre todas as solicitações que ocorrem na mesma sessão HTTP. Isso é útil quando você não salva dados de um cliente específico para uma sessão específica.

3@javax.enterprise.context.ConversationScoped .: O escopo da conversa persiste como o log que o bean vive. O escopo fornece 2 métodos: Conversation.begin()e Conversation.end(). Esses métodos devem ser chamados explicitamente, para iniciar ou finalizar a vida útil de um bean.

4@javax.enterprise.context.RequestScoped .: O escopo da solicitação é de curta duração. Inicia quando uma solicitação HTTP é enviada e termina após a resposta ser enviada de volta ao cliente. Se você colocar um bean gerenciado no escopo da solicitação, uma nova instância será criada com cada solicitação. Vale a pena considerar o escopo da solicitação se você estiver preocupado com o custo do armazenamento do escopo da sessão.

5@javax.faces.flow.FlowScoped .: O escopo do fluxo persiste enquanto o fluxo permanecer. Um fluxo pode ser definido como um conjunto contido de páginas (ou visualizações) que definem uma unidade de trabalho. O escopo definido como fluxo está ativo enquanto o usuário navega no fluxo.

6@javax.faces.view.ViewScoped .: Um escopo do bean no modo de exibição persiste enquanto a mesma página JSF é exibida novamente. Assim que o usuário navega para uma página diferente, o bean fica fora do escopo.


A resposta legada a seguir aplica a versão JSF anterior à 2.3

No JSF 2.x, existem 4 escopos de bean:

  • @SessionScoped
  • @RequestScoped
  • @ApplicationScoped
  • @ViewScoped

Escopo da sessão: o escopo da sessão persiste desde o momento em que uma sessão é estabelecida até o término da sessão. Uma sessão termina se o aplicativo Web chamar o método invalidate no objeto HttpSession ou se o tempo limite for excedido.

RequestScope: o escopo da solicitação é de curta duração. Inicia quando uma solicitação HTTP é enviada e termina após a resposta ser enviada de volta ao cliente. Se você colocar um bean gerenciado no escopo da solicitação, uma nova instância será criada com cada solicitação. Vale a pena considerar o escopo da solicitação se você estiver preocupado com o custo do armazenamento do escopo da sessão.

ApplicationScope: o escopo do aplicativo persiste por toda a duração do aplicativo da web. Esse escopo é compartilhado entre todas as solicitações e todas as sessões. Você coloca beans gerenciados no escopo do aplicativo se um único bean deve ser compartilhado entre todas as instâncias de um aplicativo Web. O bean é construído quando é solicitado pela primeira vez por qualquer usuário do aplicativo e permanece ativo até que o aplicativo da Web seja removido do servidor de aplicativos.

ViewScope: o escopo da visualização foi adicionado no JSF 2.0. Um bean no escopo de exibição persiste enquanto a mesma página JSF é exibida novamente. (A especificação JSF usa o termo view para uma página JSF.) Assim que o usuário navega para uma página diferente, o bean fica fora do escopo.

Escolha o escopo com base em seus requisitos.

Fonte: Core Java Server Faces 3rd Edition por David Geary e Cay Horstmann [Página no. 51 - 54] insira a descrição da imagem aqui

Kishor Prakash
fonte
Você poderia esclarecer, o que você quer dizer com "o método inválido no objeto HttpSession": invalidate()método ou método inválido?
Alexander Pozdneev 29/07
11
Um pouco velho e talvez atrasado para responder, mas para esclarecer: FacesContext.getCurrentInstance().getExternalContext().invalidateSession();ser invocado no seu "logout bean" é o que ele quer dizer.
Roland
11
tornou-se resposta legado, no momento há 8 escopos
Ewoks
@KishorPrakash: já faz um tempo, há 6 meses. ;-)
Kukeltje 1/11/19
@Kukeltje: Desculpe, estou nisso.
Kishor Prakash