Pergunta

Eu tenho um bean de sessão sem que contém um método público, vários métodos privados, e algumas variáveis ??nível de instância. Abaixo está um exemplo de código pseudo.

private int instanceLevelVar

public void methodA(int x) { 
  this.instanceLevelVar = x;
  methodB();
}

private void methodB() {
  System.out.println(instanceLevelVar);
}

O que eu estou vendo é que MethodB está imprimindo valores que não foram passados ??para MethodA. O melhor que pode dizer que é a impressão de valores de outras instâncias do mesmo feijão. O que poderia causar isso?

Gostaria de salientar o código funciona como esperado 99,9% do tempo. No entanto, a 0,01% está causando sérios problemas / preocupações para mim.

Eu entendo que se eu tivesse diferentes métodos públicos, então eu não poderia obter o mesmo de volta feijão entre as chamadas, o que resultaria em este comportamento. No entanto, neste caso, a única chamada é para o método público único. Será que o recipiente (Glassfish, neste caso) ainda trocar o feijão fora entre chamadas de método particulares?

(edit) I renomeado "nível de classe" para "nível de instância", pois isso estava causando alguma confusão.

Foi útil?

Solução

Eu simplesmente não se incomode com variável de instância no bean de sessão sem estado em tudo. Independentemente do que a causa do problema que encontrou, provavelmente não é algo que você iria querer fazer de qualquer maneira. Apenas tente usar variáveis ??locais em todo ou definir variáveis ??de instância em classes auxiliares que você está chamando a partir da sessão sem estado métodos de negócios do bean.

Outras dicas

Quando li O que é um Bean de sessão? seção do tutorial J2EE 1.4:

Beans de sessão sem estado

A sessão sem estado feijão não mantém um estado de conversação para um cliente particular. Quando um cliente chama o método de um feijão stateless, variáveis ??de instância do feijão pode conter um estado, mas apenas para a duração da chamada. Quando o método é concluído, o estado não é mais retida. Excepto durante a chamada de método, todas as instâncias de um feijão sem estado são equivalentes, permitindo que o recipiente EJB para atribuir um exemplo para qualquer cliente.

No seu caso, a chamada para methodB() de methodA() será na mesma instância e é equivalente a this.methodB(). Estou, portanto, tendem a dizer que methodB() algo não pode produzir mais que o valor que o que foi passado para methodA().

Isto é confirmado pela primeira frase na seção 7.11.8 na EJB 2.0 especificação : " O recipiente deve garantir que apenas um thread pode estar executando uma instância a qualquer momento" Isto significa que você não pode chegar a uma situação onde os dados (em suas variáveis ??de instância) de diferentes clientes (threads) será mista. Está assegurado o acesso exclusivo para as variáveis ??de instância até methodA() voltou!

Dito isto, eu não estou dizendo que você não tem um problema em algum lugar. Mas eu não acho que o código pseudo é equivalente.

(EDIT:.. Depois de ler alguns comentários a pergunta do OP, existe agora claramente uma dúvida sobre o código pseudo e semântica usada estou esclarecendo possíveis consequências abaixo)

Tal como sublinhado pelo cirurgião de Rocket, o que quer dizer exatamente por variável de classe ? Você realmente quer dizer variável de classe em oposição à variável de instância ? Se sim, o código pseudo não reflete isso, mas isso vai claramente levar a um comportamento imprevisível. Na verdade, a partir da secção 24.1.2 (e primeiro ponto) na especificação EJB 2.0, é claro que você não tem permissão para gravar dados a uma variável de classe (embora você pode fazê-lo). Deve haver uma boa razão para isso:)

A causa provável do problema é que o recipiente está usando o mesmo objeto em dois pedidos (portanto, dois threads) ao mesmo tempo. Assim, o primeiro segmento chega a linha que chama MethodB e, em seguida, o próximo segmento chega ao código que chama MethodB e, em seguida, o primeiro thread executa a chamada para MethodB, causando o problema. Isso explicaria o comportamento, de qualquer modo. Ele não parecem caber a especificação, mas que poderia ser apenas um bug.

Em geral, mesmo se permitido, manter o estado no bean não é uma grande idéia. Isso leva a código de confusão e pode facilmente levar a erros que você se esqueça de começar de novo com o seu todo o seu estado em cada chamada de método.

Seria muito melhor para apenas passar esses objetos ao redor entre os métodos, e que evitaria todas as questões.

Provavelmente o seu não são reinitializing adequadamente a variável de instância.

As variáveis ??de instância

Em geral, não devemos manter o estado em nosso bean de sessão sem estado. Objetos referenciados por variáveis ??de instância, se não anulado após a sua utilização, são mantidos vivos até o final do pedido e ainda mais se os nossos EJB piscinas recipiente os beans de sessão para reutilizado. Neste último caso, precisamos ter certeza de que a variável de instância obter corretamente reinicializado durante uma solicitação subseqüente. Portanto, o uso de variáveis ??de instância pode levar às seguintes questões:

  • durante o mesmo pedido, instância variável compartilhada entre diferentes métodos pode facilmente levar a erros em que se esqueça de começar de novo com o estado correto em cada chamada de método
  • em caso EJB beans de sessão piscinas recipiente e podemos nosso código não reinicializar corretamente as variáveis ??de instância que pode reutilização set estado obsoleto em um pedido anterior
  • variáveis ??de instância tem escopo instância que poderia apresentar problemas de vazamento de memória onde o espaço na pilha é usada para manter objetos que não são (ou deveriam ser não) mais usados.

Variáveis ??de classe

Quanto a variáveis ??de instância, variáveis ??de classe não deve ser usado para manter o estado compartilhado em Stateless session bean. Isso não significa que não devemos usar a palavra-chave estática, mas que devemos usá-lo com cautela (por exemplo, definir constantes imutáveis, alguma classe fábrica estática, etc.)

Porque isto é muito estranho eu realizado um teste rápido com Netbeans e meu Glassfish locais 2.1.

  1. Criar um novo projeto usando Amostras-> Java EE> Servlet Stateless. Isso cria um projeto da empresa com um feijão simples apátrida e um servlet que usa-lo.
  2. Eu modifiquei o feijão apátridas para ficar assim, tão perto de seu exemplo quanto possível, eu acho.

    @Stateless
    public class StatelessSessionBean implements StatelessSession {
    
       String clName;
    
       private void testNa() {
          System.out.println(clName);
       }
    
       public String sayHello(String name) {
          this.clName = name;
          testNa();
          return "Testcase";
       }
    }
    

Isso funciona como deveria. Eu não sei o editor que você está usando, mas se é Netbeans pode ser interessante para executá-lo a si mesmo.

tudo depende do que você entende por "variável de nível de classe". Uma variável de classe deve ter o modificador estático. Se clName não acontecer, então cada instância de seu bean de sessão sem estado tem a sua própria cópia do clName. O servidor Java EE provavelmente criado um pool de duas ou mais instâncias do bean de sessão sem estado, e cada uma de suas chamadas para testNa() e sayHello() é enviado a uma instância arbitrária.

me deparei com essa pergunta quando eu experimentei o mesmo problema. No meu caso, o método privado realmente define a variável de instância. O que tenho notado é que às vezes a variável de instância já foi definido, obviamente, de uma solicitação anterior.

@Stateless
public class MyBean {
  String someString;

  public void doSomething() {
    internalDoSomething();
  }

  private void internalDoSomething() {
    if (someString != null) {
      System.out.println("oops, someString already contained old data");
    }

    this.someString = "foo";
  }
}

Eu acho que faz sentido. Quando o recipiente re-utiliza uma instância em cache, como deve saber como limpar as variáveis ??...

Para mim, isso está em linha com e confirma ambos referência de Pascal com a especificação EJB ( "variáveis ??de instância são suportados") e foguete recomendação do cirurgião ( "não fazê-lo, use as variáveis ??locais em vez").

O problema com o uso de variáveis ??de instância em feijões de apátridas.

De acordo com a especificação JEE a mesma instância EJB apátrida pode ser compartilhado com outro cliente também. A regra de ouro não é para criar variáveis ??de instância em Stateless EJBs.

Pode ser possível os dois clientes que acessam o aplicativo simultaneamente são fornecidos mesma instância EJB que criaria problemas uma vez que há inconsistência de dados.

Portanto, não é uma boa idéia para variáveis ??uso instância em feijão EJB apátridas.

Eu tive problema semelhante porque eu usei variável global classe estática em minha classe EJB e quando eu tinha EJB apátrida concorrente em execução, variável foi substituído por outras instâncias.

campos de classe estáticas são compartilhadas entre todas as instâncias de uma classe particular, mas apenas dentro de uma única Java Virtual Machine (JVM). A atualização do campo classe estática implica a intenção de compartilhar o valor do campo entre todas as instâncias da classe.

Hope ajuda de outra pessoa:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top