Por que o JSF salva o estado dos componentes da IU no servidor?

108
  1. Até que ponto no tempo o JSF salva o estado dos componentes da UI no lado do servidor e quando exatamente as informações de estado do componente da UI são removidas da memória do servidor? Conforme um usuário logado no aplicativo navega pelas páginas, o estado dos componentes continuará se acumulando no servidor?

  2. Não entendo qual é a vantagem de manter o estado dos componentes da IU no servidor !? Não é suficiente passar diretamente os dados validados / convertidos para beans gerenciados? Posso ou devo tentar evitá-lo?

  3. Isso não consome muita memória no lado do servidor, se houver milhares de sessões de usuário simultâneas? Eu tenho um aplicativo onde os usuários podem postar blogs sobre determinados tópicos. Esses blogs são muito grandes. Quando houver postagem ou solicitação de visualização dos blogs, esses dados do big page serão salvos como parte do estado dos componentes? Isso consumiria muita memória. Isso não é uma preocupação?


Atualização 1:

Agora, não é mais necessário salvar o estado ao usar o JSF. Uma implementação JSF sem estado de alto desempenho está disponível para uso. Veja este blog e esta pergunta para detalhes e discussões relevantes. Além disso, há um problema em aberto para incluir nas especificações JSF, uma opção para fornecer modo sem estado para JSF. (PS Considere votar nas questões deste e deste se este for um recurso útil para você.)


Atualização 2 (24-02-2013):

Uma ótima notícia que o Mojarra 2.1.19 está com o modo sem estado !

Veja aqui:

http://weblogs.java.net/blog/mriem/archive/2013/02/08/jsf-going-stateless?force=255

http://java.net/jira/browse/JAVASERVERFACES-2731

http://balusc.blogspot.de/2013/02/stateless-jsf.html

Rajat Gupta
fonte

Respostas:

199

Por que o JSF precisa salvar o estado dos componentes da IU no servidor?

Porque o HTTP não tem estado e o JSF tem estado. A árvore de componentes JSF está sujeita a alterações dinâmicas (programáticas). O JSF simplesmente precisa saber o estado exato em que estava quando o formulário foi exibido para o usuário final, para que possa processar com êxito todo o ciclo de vida do JSF com base nas informações fornecidas pela árvore de componentes JSF original quando o formulário foi enviado de volta para o servidor. A árvore de componentes fornece informações sobre os nomes dos parâmetros de solicitação, os conversores / validadores necessários, as propriedades de bean gerenciado vinculado e métodos de ação.


Até que ponto no tempo o JSF salva o estado dos componentes da UI no lado do servidor e quando exatamente as informações de estado do componente da UI são removidas da memória do servidor?

Essas duas perguntas parecem resumir-se na mesma. De qualquer forma, isso é específico da implementação e também depende se o estado é salvo no servidor ou cliente. Uma implementação um pouco decente o removerá quando ele tiver expirado ou quando a fila estiver cheia. Mojarra, por exemplo, tem um limite padrão de 15 visualizações lógicas quando o salvamento de estado é definido como sessão. Isso é configurável com o seguinte parâmetro de contexto em web.xml:

<context-param>
    <param-name>com.sun.faces.numberOfLogicalViews</param-name>
    <param-value>15</param-value>
</context-param>

Consulte também Mojarra FAQ para outros parâmetros específicos de Mojarra e esta resposta relacionada com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews


Conforme um usuário logado no aplicativo navega pelas páginas, o estado dos componentes continuará se acumulando no servidor?

Tecnicamente, isso depende da implementação. Se você está falando sobre navegação página a página (apenas solicitações GET), o Mojarra não salvará nada na sessão. No entanto, se forem solicitações POST (formulários com links de comando / botões), o Mojarra salvará o estado de cada formulário na sessão até o limite máximo. Isso permite que o usuário final abra vários formulários em diferentes guias do navegador na mesma sessão.

Ou, quando o salvamento de estado é definido como cliente, o JSF não armazenará nada na sessão. Você pode fazer isso através do seguinte parâmetro de contexto em web.xml:

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

Em seguida, ele será serializado em uma string criptografada em um campo de entrada oculto com o nome javax.faces.ViewStatedo formulário.


Eu não entendo qual é a vantagem de manter o estado do componente de interface do usuário no lado do servidor. Não é suficiente passar diretamente os dados validados / convertidos para beans gerenciados? Posso / devo tentar evitá-lo?

Isso não é suficiente para garantir a integridade e robustez do JSF. JSF é uma estrutura dinâmica com um único ponto de controle de entrada. Sem um gerenciamento de estado, seria possível falsificar / hackear solicitações HTTP de uma determinada maneira (por exemplo disabled, manipulação readonlye renderedatributos), para permitir que o JSF fizesse coisas diferentes - e potencialmente perigosas. Estaria até sujeito a ataques CSRF e phishing.


E isso não vai consumir muita memória no lado do servidor, se houver milhares de sessões de usuário simultâneas? Eu tenho um aplicativo onde os usuários podem postar blogs sobre determinados tópicos. Esses blogs são muito grandes. Quando houver postagem de volta ou solicitação de visualização dos blogs, os grandes blogs serão salvos como parte do estado dos componentes. Isso consumiria muita memória. Isso não é uma preocupação?

A memória é particularmente barata. Basta dar ao appserver memória suficiente. Ou se a largura de banda da rede for mais barata para você, basta alternar a economia de estado para o cliente. Para encontrar a melhor correspondência, apenas teste e crie o perfil de seu webapp com a quantidade máxima esperada de usuários simultâneos e, em seguida, dê ao appserver 125% ~ 150% da memória máxima medida.

Observe que o JSF 2.0 melhorou muito no gerenciamento de estado. É possível salvar o estado parcial (por exemplo, apenas o <h:form>será salvo em vez de todo o material de <html>todo o caminho até o fim). Mojarra, por exemplo, faz isso. Um formulário médio com 10 campos de entrada (cada um com um rótulo e uma mensagem) e 2 botões não ocuparia mais do que 1 KB. Com 15 visualizações na sessão, isso não deve ser superior a 15 KB por sessão. Com aproximadamente 1000 sessões de usuário simultâneas, isso não deve ser superior a 15 MB.

Sua preocupação deve estar mais focada nos objetos reais (beans gerenciados e / ou mesmo entidades de banco de dados) no escopo da sessão ou do aplicativo. Já vi muitos códigos e projetos que duplicam desnecessariamente toda a tabela do banco de dados na memória do Java, como um bean com escopo de sessão em que o Java é usado em vez de SQL para filtrar / agrupar / organizar os registros. Com ~ 1000 registros, isso ultrapassaria facilmente 10 MB por sessão de usuário .

BalusC
fonte
1
Você pode esclarecer o nº 2? Por que a árvore de componentes não pode ser recriada em cada solicitação? Qual estado realmente precisa ser armazenado entre as solicitações e por quê? Parece que o único motivo para salvar a árvore de componentes entre as solicitações seria para desempenho.
Ryan,
Pergunta mais focada aqui: stackoverflow.com/questions/7349174/…
Ryan
Sua resposta foi muito clara para mim! As questões sobre desempenho e escalabilidade do JSF têm relação intrínseca com a implementação do programador! É preciso saber usar a tecnologia da maneira certa!
Lucas Batistussi
"Basta dar ao appserver memória suficiente." Hmm, tenho a impressão de que estamos falando de coisas de nível empresarial aqui, se estamos falando de milhares de sessões de usuário simultâneas. Se você tem um equipamento de nível corporativo em uma empresa, você não pode simplesmente "dar ao appserver memória suficiente" como faria em sua caixa Linux em casa.
stu
Sua resposta foi muito clara e obrigado por isso. Por que o escopo do JSF Flash desapareceu se definido javax.faces.PARTIAL_STATE_SAVING como true. getFacesContext (). getExternalContext (). getFlash (). put ("buildingId", buildingId).
Quarta de maio