Stateless session bean with instance variables

2019-01-22 08:42发布

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.

9条回答
再贱就再见
2楼-- · 2019-01-22 09:16

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.

查看更多
Evening l夕情丶
3楼-- · 2019-01-22 09:19

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.)

查看更多
Fickle 薄情
4楼-- · 2019-01-22 09:27

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 :)

查看更多
小情绪 Triste *
5楼-- · 2019-01-22 09:30

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.

查看更多
我只想做你的唯一
6楼-- · 2019-01-22 09:34

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.

查看更多
Root(大扎)
7楼-- · 2019-01-22 09:36

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 :)

查看更多
登录 后发表回答