現實中,不少朋友對兩種session bean存在誤解,認爲有狀態是實例一直存在,保存每次調用後的狀態,並對下一次調用起做用,而認爲無狀態是每次調用實例化一次,不保留用戶信息。仔細分析並用實踐檢驗後,你會發現,事實剛好相反:
有狀態和無狀態會話bean的本質區別是它們的生命期。
首先解釋一個下面要用到的概念--用戶:session bean 的用戶實際上就是直接調用ejb的類的實例,甚至是這個實例的某個方法。同一個類的不一樣實例對於session bean 來講是不一樣的用戶。
有狀態會話bean :每一個用戶有本身特有的一個實例,在用戶的生存期內,bean保持了用戶的信息,即「有狀態」;一旦用戶滅亡(調用結束或實例結束),bean的生命期也告結束。即每一個用戶最初都會獲得一個初始的bean。
無狀態會話bean :bean一旦實例化就被加進會話池中,各個用戶均可以共用。即便用戶已經消亡,bean 的生命期也不必定結束,它可能依然存在於會話池中,供其餘用戶調用。因爲沒有特定的用戶,那麼也就不能保持某一用戶的狀態,因此叫無狀態bean。但無狀態會話bean 並不是沒有狀態,若是它有本身的屬性(變量),那麼這些變量就會受到全部調用它的用戶的影響,這是在實際應用中必須注意的。
1.無狀態會話Bean
從字面意思來理解,無狀態會話Bean是沒有可以標識它的目前狀態的屬性的Bean。例如:
public class A {
public A() {}
public String hello() {
return "Hello 誰?";
}
}
public class Client {
public Client() {
A a = new A();
System.out.println(a.hello());
A b = new A();
System.out.println(b.hello());
}
}
在Client中生成了兩個A的實例,不論是對象a仍是b,它們是沒有狀態的。對於Client來講a和b是沒有差異的(但a != b)。因此同一個無狀態會話Bean的實例都是相同的,能夠被不一樣的客戶端重複使用。
2.狀態會話Bean
至於狀態會話Bean,能夠這樣理解:它是有存儲能力的。也就是說至少有一個屬性來標識它目前的狀態。例如:
public class B {
private String name;
public B(String arg) {
this.name = arg;
}
public String hello() {
return "Hello" + this.name;
}
}
public class Client {
public Client() {
B a = new B("中國");
System.out.println(a.hello());
B b = new B("世界");
System.out.println(b.hello());
}
}
3.調度池:
其實調度池的概念同數據鏈接池概念基本相同,都是爲了提升系統性能而設計的。就像是餃子館同樣,餃子的作法能夠有兩種,一種是無論當前有沒有客人,先將一些餃子下鍋,等到客人來後能夠立刻撈出來給客人吃。還有一種是客人來後纔將餃子下鍋。這個例子顯然不是十分恰當,但它的確能說明問題。調度池的概念就像是餃子的第一種作法同樣,先將一些Bean實例放入池中,(也就是緩存起來,具體緩存多少取決於不一樣的容器)等到客戶端調用時直接能夠取來使用。它和餃子的區別仍是很大的,要是餃子下鍋後沒有客人來吃可慘了
4.無狀態會話Bean實現調度池調度:
由於無狀態會話Bean是不保存會話狀態的,因此不管哪一個客戶端調用了某個無狀態會話Bean,都沒有差異,也就是說任何一個無狀態會話Bean的實例均可覺得客戶端程序提供服務。並且無狀態會話Bean同客戶端的關係是1:n。也就是說,同一個會話Bean實例能夠供不一樣客戶端使用。所以無狀態會話Bean能夠被存儲在調度池中,供不一樣客戶端重用。
5.狀態會話Bean實現調度池調度:
由於狀態會話Bean是保持當前會話的狀態的,因此實現起來遠比無狀態會話Bean困難。由於它要保存會話狀態,但物理內存的空間是有限的,想要保存n多客戶端當前會話狀態是不可能的。EJB容器採起了同操做系統相同的作法,將狀態會話Bean對話狀態保存在硬盤或其它存儲器中(鈍化passivation)。當被鈍化的Bean原先的客戶端調用其方法時,被鈍化的狀態從新交還給Bean(激活activation)。也許容器把被鈍化的狀態交還給不一樣的Bean實例,那又有什麼關係呢?只要這個Bean實例能跟原先鈍化以前的那個Bean實例如出一轍就好了。事實上它的確如出一轍:)大多數容器採用最近最少被使用(Least Recently Used:LRU)的鈍化策略。由於客戶端是不可能一直在執行操做,他可能在看新聞或其它什麼的。因此以這種方式鈍化Bean是很是合理有效的。但有一個例外:正在進行事務處理的Bean必定要等到事務處理完畢後才能被鈍化。大多數容器採用根據須要被激活(Just-in-time)的策略。客戶有請求,ok沒問題,激活那個被鈍化了的Bean:)注:鈍化和激活跟無狀態會話Bean不要緊。緩存