Stateless session bean with instance variables
Asked Answered
C

9

15

I have a stateless session bean that contains one public method, several private methods, and some instance level variables. Below is a pseudo code example.

private int instanceLevelVar

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

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

What I'm seeing is that methodB is printing values that weren't passed into MethodA. As best I can tell it's printing values from other instances of the same bean. What would cause this?

I should point out the code works as expected 99.9% of the time. However, the .01% is causing some serious issues / concerns for me.

I understand that if I had different public methods then I might not get the same bean back between calls, which would result in this behavior. However, in this case the only call is to the single public method. Will the container (Glassfish in this case) still swap the beans out between private method calls?

(edit) I renamed "class level" to "instance level" as this was causing some confusion.

Carolynncarolynne answered 27/10, 2009 at 0:7 Comment(8)
That's quite strange. Are you sure your pseudocode really reflects what your actual code does?Slither
When calling methodB() from methodA(), there is no remote call so this should behave like any normal class IMHO. Actually, it wouldn't make sense to swap beans for a private method, private methods aren't even remote...Nyasaland
@Slither agreed, this should just work. I can't see any issue.Nyasaland
It's accurate in that I only have 1 public method. I do have multiple class level variables and multiple private methods. However, all variables are set from within the public method. It's as if the container suspends processing halfway through and then lets another client start processing with the same bean, suspends that and returns control back to the original client. Now all the class variables have changed.Carolynncarolynne
did you try making "classLevelVar" private? I see it has default access now.Sandisandidge
also, "class level variable" - if it's a class variable it has to be declared with "static" keyword. That would explain this behavior. Your code and variable name are contradicting each other.Sandisandidge
I'm calling it a class level variable just because it has scope to the class. The actual declaration looks like private int x;Carolynncarolynne
@Carolynncarolynne - just FYI, here is some formal definitions of class/instance/local variables in Java: leepoint.net/notes-java/data/variables/45local-inst-class.htmlSandisandidge
S
10

I would just not bother using instance variable in stateless session bean at all. Regardless of what the cause of the issue you have encountered, it's probably not something you would want to do anyway. Just try using local variables throughout or define instance variables in helper classes you are calling from the stateless session bean business methods.

Sandisandidge answered 27/10, 2009 at 17:8 Comment(2)
one of my team members is saying the same thing.Carolynncarolynne
Same as for servlets. I can tell some stories about people who write servlets and assume the web container creates a new servlet instance just for "their" thread. Nyet! Functional style and variables only-on-stack are your friends here.Stamata
N
25

When I read What is a Session Bean? section of the J2EE 1.4 tutorial:

Stateless Session Beans

A stateless session bean does not maintain a conversational state for a particular client. When a client invokes the method of a stateless bean, the bean's instance variables may contain a state, but only for the duration of the invocation. When the method is finished, the state is no longer retained. Except during method invocation, all instances of a stateless bean are equivalent, allowing the EJB container to assign an instance to any client.

In your case, the call to methodB() from methodA() will be on the same instance and is equivalent to this.methodB(). I'm thus tend to say that methodB() can't output something else that the value that what was passed to methodA().

This is confirmed by the first sentence in section 7.11.8 in the EJB 2.0 spec: "The container must ensure that only one thread can be executing an instance at any time". This means you cannot come to a situation where data (in your instance variables) from different clients (threads) will be mixed. You are ensured unique access to the instance variables until methodA() has returned!

That said, I'm not saying that you don't have a problem somewhere. But I don't think that your pseudo code is equivalent.

(EDIT: Having read some comments to the OP's question, there is now clearly a doubt about the pseudo code and semantic used. I'm clarifying possible consequences below.)

As underlined by Rocket Surgeon, what do you mean exactly by class variable? Do you really mean class variable as opposed to instance variable? If yes, the pseudo code doesn't reflect it but this will clearly lead to unpredictable behavior. Actually, from section 24.1.2 (and first point) in the EJB 2.0 spec, it is clear that you are not allowed to write data to a class variable (although you can do it). There must be a good reason for this :)

Nyasaland answered 27/10, 2009 at 0:56 Comment(7)
I'm calling it a class level variable just because it has scope to the class as opposed to a method level variable. The actual declaration looks like private int x;Carolynncarolynne
The EJB spec also says "Because all instances of a stateless session bean are equivalent, the container can choose to delegate a client-invoked method to any available instance. This means, for example, that the container may delegate the requests from the same client within the same transaction to different instances, and that the container may interleave requests from multiple transactions to the same instance." It's the last part of the last sentence that makes me wonder. "and that the container may interleave requests from multiple transactions to the same instance"Carolynncarolynne
@Pascal, so apparently this is an EJB 3.0 spec question, not 2.1Sandisandidge
@Rocket Mmm, the OP wrote "Because all instances of a stateless session bean are equivalent, the container can choose to delegate a client-invoked method to any available instance. This means, for example, that the container may delegate the requests from the same client within the same transaction to different instances, and that the container may interleave requests from multiple transactions to the same instance." which is in EJB 2.x spec. But I'm doubting now, I'd like the OP to confirm.Nyasaland
@Pascal Yes, this was for the ejb 3.0 spec. Thanks for the help!Carolynncarolynne
@Carolynncarolynne @Rocket This still holds for EJB 3.0, the behavior is the same, the version of the spec is not the important part.Nyasaland
If Stateless session Bean is returned back to pool, Does the instance variable values will be reset?. So when container assign the same bean from the pool to another thread,bean comes back with default instance variable values. Am I correct?Houri
S
10

I would just not bother using instance variable in stateless session bean at all. Regardless of what the cause of the issue you have encountered, it's probably not something you would want to do anyway. Just try using local variables throughout or define instance variables in helper classes you are calling from the stateless session bean business methods.

Sandisandidge answered 27/10, 2009 at 17:8 Comment(2)
one of my team members is saying the same thing.Carolynncarolynne
Same as for servlets. I can tell some stories about people who write servlets and assume the web container creates a new servlet instance just for "their" thread. Nyet! Functional style and variables only-on-stack are your friends here.Stamata
D
5

The likely cause of the issue is that the container is using the same object in two requests (therefore two threads) at the same time. So the first thread gets to line that calls methodB and then the next thread gets to the code which calls methodB and then the first thread executes the call to methodB, causing the issue. That would explain the behavior, at any rate. It doesn't seem to fit the spec, but that could just be a bug.

In general, even if permitted, keeping state in the bean is not a great idea. It leads to confusion code and can easily lead to bugs where you forget to start over with your all your state on every method call.

It would be much better to just pass those objects around between methods, and that would avoid all issues.

Disputant answered 27/10, 2009 at 17:19 Comment(0)
N
3

Probably your are not properly reinitializing the instance variable.

Instance variables

In general we should not keep state in our stateless session bean. Objects referenced by instance variables, if not nulled after their use, are kept alive until the end of the request and even longer if our EJB container pools the session beans to reused. In the latter case we need to make sure that instance variable get properly reinitialized during a subsequent request. Therefore the use of instance variables may lead to the following issues:

  • during the same request, instance variable shared between different methods can easily lead to bugs where we forget to start over with the correct state on every method call
  • in case EJB container pools session beans and we may our code fails to properly reinitialize the instance variables we may reuse stale state set in a previous request
  • instance variables have instance scope which could introduce memory leak problems where space in the Heap is used to keep objects that are not (or should be not) used anymore.

Class variables

As for instance variables, class variables should not be used to keep shared state in Stateless session bean. This does not mean we should not use the static keyword but that we should use it with caution (e.g. define immutable constants, some static factory class, etc.)

Nostril answered 5/1, 2014 at 20:37 Comment(0)
S
2

Because this is very strange I performed a quick test with Netbeans and my local Glassfish 2.1.

  1. Create a new project using Samples->Java EE->Servlet Stateless. This creates an enterprise project with a simple stateless bean and a servlet that uses it.
  2. I modified the stateless bean to look like this, as close to your example as possible I think.

    @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";
       }
    }
    

This works as it should. I don't know what editor you're using, but if it's Netbeans it may be interesting to run it yourself.

Slither answered 27/10, 2009 at 0:54 Comment(6)
The code is considered as nested in the list, it needs 8 blanks oONyasaland
The example you have looks right. However, it think the problem only occurs when there are multiple beans in use. I'm going to to try and write some test code and use some load software to see if I can reproduce a hit.Carolynncarolynne
@Slither Is this EJB 3.0? I think question was specifically about EJB 2.1Sandisandidge
@RocketSurgeon, as Preston mentioned that he works on a GlassFish container I more or less assumed 3.0. I don't see any reference to 2.1 in the original question, there's just a quote from the 2.1 spec by Pascal Thivent in another answer.Slither
@Carolynncarolynne was the test I proposed useful to you?Slither
@Slither I still haven't tried developing a load test yet, but yes it was useful.Carolynncarolynne
A
1

The problem with using Instance variables in stateless Beans.

According to the JEE specification that same stateless EJB instance might be shared with another client as well. The thumb rule is not to create instance variables in Stateless EJBs.

It might be possible the two clients accessing the application simultaneously are provided same EJB instance which would create problems since there is data inconsistency.

So it is not a good idea to use instance variables in stateless EJB beans .

Atticism answered 23/9, 2016 at 14:31 Comment(0)
C
1

I had similar issue because I used global static class variable in my ejb class and when I had concurrent stateless EJB running, variable was overwritten by other instances.

Static class fields are shared among all instances of a particular class, but only within a single Java Virtual Machine (JVM). Updating a static class field implies an intent to share the field's value among all instances of the class.

Hope help someone else :)

Cantone answered 15/5, 2017 at 10:12 Comment(0)
H
0

It all hinges on what you mean by "class level variable". A class variable must have the static modifier. If clName doesn't, then each instance of your stateless session bean has its own copy of clName. Your Java EE server probably created a pool of two or more instances of the stateless session bean, and each of your calls to testNa() and sayHello() gets sent to an arbitrary instance.

Heisenberg answered 27/10, 2009 at 2:23 Comment(3)
I'm calling it a class level variable just because it has scope to the class as opposed to a method level variable. The actual declaration looks like private int x;Carolynncarolynne
So you're saying that public call to sayHello might be handled by bean 1 and the private call to testNa might be handled by bean 2?Carolynncarolynne
Yes, or in the current example, you call methodA() of one bean and methodB() of another, etc. Since each bean (object) has its own instanceLevelVar, if you were expecting instanceLevelVar to be shared by all the beans in your class, you'd be surprised by the results.Heisenberg
C
0

I stumbled upon this question when I experienced the same problem. In my case, the private method actually sets the instance variable. What I have noticed is that sometimes the instance variable was already set, obviously from a previous request.

@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";
  }
}

I guess it makes sense. When the container re-uses a cached instance, how should it know how to clear the variables...

To me, this is inline with and confirms both Pascal's reference to the EJB spec ("instance variables are supported") and Rocket Surgeon's recommendation ("don't do it, use local variables instead").

Copier answered 24/8, 2011 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.