此文整理自論壇的一個討論文章,我已經加精
其中 35樓的huangwen9 以及 37 樓的huangpeihp 給出了正確的解釋。
原文章在這裡:http://topic.csdn.net/u/20080410/16/59a5734b-d4b5-490d-a4ab-9f63dc7a2708.html
系統現象
1 測試的Bean為
package net.java2000.html;
public class CounterBean ...{
private int count = 0;
public CounterBean() ...{
}
public int getCount() ...{
return count;
}
public void setCount(int count) ...{
this.count = count;
}
}
2 測試的 JSP 為
<jsp:useBean id="myBean" scope="session" class="net.java2000.html.CounterBean" />
<jsp:getProperty name="myBean" property="count" />
<br>
<%=myBean.getCount()%>
<jsp:setProperty name="myBean" property="count" value="<%=myBean.getCount()+1%>" />
3 運行結果為
0
0
重新整理後為
1
1
重新整理後為
2
2
重新整理後為
3
3
4 OK,如果我們現在把jsp檔案裡面的 session 改成 application
<jsp:useBean id="myBean" scope="application" class="net.java2000.html.CounterBean" />
<jsp:getProperty name="myBean" property="count" />
<br>
<%=myBean.getCount()%>
<jsp:setProperty name="myBean" property="count" value="<%=myBean.getCount()+1%>" />
5 運行結果為
第一次重新整理
4
0
第二次重新整理
1
0
第三次重新整理
1
0
以後無論如何重新整理,都是著個數字
難道是jsp的bug?
系統分析
1 我們先查看一下產生的原始碼
net.java2000.html.CounterBean myBean = null;
synchronized (application) ...{
// #######注意這裡 1 ############
myBean = (net.java2000.html.CounterBean) _jspx_page_context.getAttribute("myBean", PageContext.APPLICATION_SCOPE);
if (myBean == null)...{
myBean = new net.java2000.html.CounterBean();
_jspx_page_context.setAttribute("myBean", myBean, PageContext.APPLICATION_SCOPE);
}
}
out.write(' ');
out.write(' ');
// #######注意這裡 2 ############
out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((net.java2000.html.CounterBean)_jspx_page_context.findAttribute("myBean")).getCount())));
out.write(" ");
out.write("
");
// #######注意這裡 3 ############
out.print(myBean.getCount());
out.write(' ');
out.write(' ');
// #######注意這裡 4 ############
org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty(_jspx_page_context.findAttribute("myBean"), "count",
myBean.getCount()+1);
2 我們來看一下那個 findAttribute方法的說明
/** *//**
* Searches for the named attribute in page, request, session (if valid),
* and application scope(s) in order and returns the value associated or
* null.
*
* @param name the name of the attribute to search for
* @return the value associated or null
* @throws NullPointerException if the name is null
*/
abstract public Object findAttribute(String name);
3 問題就在於那個 findAttribute
是按照順序從 page, request, session (if valid),和 application 順序尋找的,如果在前一個找到,則會返回。
1)我們的程式一開始為session,所以數字很規律的從0漲到了3,此時session裡面的數字為4
2)當我們修改application時,此時myBean變成了一個新的對象,並儲存在PageContext.APPLICATION_SCOPE中,其數值為0
3)當運行到 #2 的輸出時,由於session並沒有失效,其findAttribute會優先查到session裡面同名的myBean,所以輸出了那個4
4)#3 輸出的是我們建立的對象,所謂數字為0
5)#4 的地方是有點奇怪的,他把我們建立的myBean對象的數值+1, 然後儲存到了 session 的 myBean 裡面,數字為0+1 = 1;
4 再次重新整理
1) #1 沒啥特殊的,拿到了那個為0的對象
2) #2 由於上一次重新整理,所以數值為1
3) $3 依然是0
4) 再一次重複了前一次重新整理的步驟, 0+1=1 然後儲存到了session裡面
總結:
由於findAttriute的特殊性,所以在使用的時候要注意,必要時重啟容器是一個很簡單,但有效解決方案。
就如同作業系統有問題,解決不了,幹錯重啟機器是一樣的。呵呵!
延伸:
如果一開始為 application, 重新整理4次後,改成session會怎樣嗎??