Estou seguindo o tutorial Java EE 6 e estou tentando entender a diferença entre beans de sessão sem estado e com estado. Se os beans de sessão sem estado não retêm seu estado entre as chamadas de método, por que meu programa está agindo da maneira que está?
package mybeans;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
@LocalBean
@Stateless
public class MyBean {
private int number = 0;
public int getNumber() {
return number;
}
public void increment() {
this.number++;
}
}
O cliente
import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import mybeans.MyBean;
import java.io.PrintWriter;
@WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
public class ServletClient extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
MyBean mybean;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
mybean.increment();
out.println(mybean.getNumber());
}
}
Eu esperava que getNumber retornasse 0 todas as vezes, mas está retornando 1 e as recargas do servlet em meu navegador o aumentam ainda mais. O problema está no meu entendimento de como funcionam os beans de sessão sem estado e não com as bibliotecas ou o servidor de aplicativos, é claro. Alguém pode me dar um exemplo simples do tipo hello world de um bean de sessão sem estado que se comporta de maneira diferente quando você o altera para com estado?
java
jakarta-ee
ejb
ejb-3.1
stateful-session-bean
Stanley Kelly
fonte
fonte
Respostas:
A diferença importante não são as variáveis de membro privadas, mas a associação de estado a um usuário específico (pense em "carrinho de compras").
A parte com estado do bean de sessão com estado é como a sessão em servlets. Os beans de sessão com estado permitem que seu aplicativo ainda tenha aquela sessão, mesmo se não houver um cliente web. Quando o servidor de aplicativos busca um bean de sessão stateless fora do pool de objetos, ele sabe que pode ser usado para satisfazer QUALQUER solicitação, porque não está associado a um usuário específico.
Um bean de sessão stateful deve ser distribuído ao usuário que o obteve em primeiro lugar, porque as informações do carrinho de compras devem ser conhecidas apenas por ele. O servidor de aplicativos garante isso. Imagine o quão popular seu aplicativo seria se você pudesse começar a comprar e o servidor de aplicativos me desse seu bean de sessão com estado quando eu aparecesse!
Portanto, seu membro de dados privados é de fato "estado", mas não é "carrinho de compras". Tente refazer seu (muito bom) exemplo para torná-lo de forma que a variável incrementada seja associada a um usuário específico. Incremente-o, crie um novo usuário e veja se ele ainda pode ver o valor incrementado. Se feito corretamente, cada usuário deve ver apenas sua versão do contador.
fonte
Beans de sessão sem estado (SLSB) não estão vinculados a um cliente e não há garantia de que um cliente obtenha a mesma instância com cada chamada de método (alguns contêineres podem criar e destruir beans com cada sessão de chamada de método, esta é uma decisão específica da implementação , mas as instâncias são normalmente agrupadas - e não menciono os ambientes em cluster). Em outras palavras, embora os beans sem estado possam ter variáveis de instância, esses campos não são específicos para um cliente, portanto, não conte com eles entre chamadas remotas.
Em contraste, Stateful Session Beans (SFSB) são dedicados a um cliente por toda a sua vida, não há troca ou agrupamento de instâncias (pode ser removido da memória após a passivação para economizar recursos, mas isso é outra história) e manter o estado de conversação . Isso significa que as variáveis de instância do bean podem manter os dados relativos ao cliente entre as chamadas de método. E isso torna possível ter chamadas de método interdependentes (as alterações feitas por um método afetam chamadas de método subsequentes). Processos de várias etapas (um processo de registro, um carrinho de compras, um processo de reserva ...) são casos de uso típicos para SFSB.
Mais uma coisa. Se estiver usando SFSB, você deve evitar injetá-los em classes que são multithreaded por natureza, como Servlets e beans gerenciados JSF (você não quer que eles sejam compartilhados por todos os clientes). Se quiser usar o SFSB em seu aplicativo da web, você precisará executar uma pesquisa JNDI e armazenar a instância EJB retornada no
HttpSession
objeto para atividades futuras. Algo parecido:fonte
Stateless e stateful neste contexto não significam exatamente o que você poderia esperar.
Statefulness com EJBs refere-se ao que chamo de estado de conversação . O exemplo clássico é uma reserva de voo. Se consistir em três etapas:
Imagine que cada um deles é uma chamada de método para um bean de sessão. Um bean de sessão com preservação de estado pode manter esse tipo de conversação para que se lembre do que acontece entre as chamadas.
Os beans de sessão sem estado não têm essa capacidade para o estado conversacional.
Variáveis globais dentro de um bean de sessão (sem estado ou com estado) são algo totalmente diferente. Os beans de sessão stateful terão um pool de beans criado (já que um bean só pode ser usado em uma conversa por vez) enquanto os beans de sessão stateless geralmente terão apenas uma instância, o que fará com que a variável global funcione, mas eu não acho isso é necessariamente garantido.
fonte
As principais diferenças entre os dois tipos principais de beans de sessão são:
Feijão sem estado
Stateful Beans
fonte
Isso acontece porque o contêiner possui apenas uma instância de bean no pool que está sendo reutilizada para todas as chamadas. Se você executar os clientes em paralelo, verá um resultado diferente porque o contêiner criará mais instâncias de bean no pool.
fonte
Tem boas respostas. Eu gostaria de adicionar uma pequena resposta. O Bean sem estado não deve ser usado para armazenar dados do cliente. Deve ser usado para "modelar ações ou processos que podem ser feitos de uma só vez".
fonte
Boa pergunta,
tente este código (altere MyBean Stateful / Stateless.):
Servlet_1
Servlet_2
case: MyBean - @ Stateless
http: // localhost: 8080 / MYServletDemo / ServletClient
1
http: // localhost: 8080 / MYServletDemo / ServletClient
2
http: // localhost: 8080 / MYServletDemo_war_exploded / newServletClient
3
http: // localhost: 8080 / MYServletDemo / ServletClient
4
case: MyBean - @ Stateful
http: // localhost: 8080 / MYServletDemo / ServletClient
1
http: // localhost: 8080 / MYServletDemo / ServletClient
2
http: // localhost: 8080 / MYServletDemo / newServletClient
1
http: // localhost: 8080 / MYServletDemo / ServletClient
3
fonte