每個屬性都是一個物件,被設定在三種Servlet API(Context、Request、Session)上
其組成可以簡單的分成String型別的名稱與Object類別的值,並被存放在Map類別實例變數上
這篇筆記會接續上篇,討論屬性與多執行緒產生的問題
Context的作用領域能讓應用程式的每個部分存取
但這也造成了一個缺點,就是沒有辦法達到執行緒安全(thread-safe)
假使將doGet() 等method增加 synchronized 宣告
卻會使Servlet一次只能服務一個客戶,而失去了並行性這個最大的好處
更糟的是這個方法沒有效果,因為只能限制同一個Servlet無法重複讀取Context屬性
其他的JSP或是Servlet依然可以存取,造成屬性的值的變動並不如我們預期
該被鎖定的不是Servlet,而是Context!
程式撰寫如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
synchronized (getServletContext()) {
getServletContext().setAttribute("a", 1);
out.println(getServletContext().getAttribute("a"));
}
........
}
synchronized鎖住的範圍正是Context相關處理的部分
注意這樣雖然已經是最好的解決之道,但一定會降低處理效率
撰寫時放在synchronized裡的程式碼越短越好
執行緒安全的問題也會發生在session處理上
session的應用在於保存客戶端的對話的狀態
一般來說,session只針對單一客戶做處理,所以執行緒安全問題比較容易被忽視
有問題的原因在於若同一個用戶同時開啟多個瀏覽器,在container的判斷上會是多個 Instance
雖然這種情形發生機會較少,但一樣不可忽視
處理方式類似上面範例程式碼:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
synchronized (session) {
session.setAttribute("a", 1);
out.println(session.getAttribute("a"));
}
.........
}
真正達到執行緒安全的是Request屬性及區域變數
這也提示了撰寫Servlet時最好以區域變數取代實例變數
request本身的setAttribute()、getAttribute()、removeAttribute()
能有傳遞變數的作用
如果應用程式需要多個Servlet來完成請求
程式範例:
request.setAttribute("a", 1);
RequestDispatcher view = request.getRequestDispatcher("test.jsp");
view.forward(request, response);
取得RequestDispatcher時也可以附加查詢字串
RequestDispatcher只有兩個method - include() & forward()
include() 一般並不常在Servlet中被使用,但是JSP常用的<jsp:include>即是使用這個方法
forward()則是回應client端的同時也轉發給另一個Servlet
RequestDispatcher的取得方法有兩種,從 ServletRequest 或是 ServletContext 取得
但不論是哪一種都必須指明所要轉交的路徑
跟之前筆記提過的的sendRedirect()可以做個比較
sendRedirect()裡輸入的路徑若以 "/" 開頭,container會建立一個相對於container本身的URL
getRequestDispatcher()則是相對於本Web Application的URL
不加 "/" 開頭的URL則都一樣是相對當前目錄位置,當前應用程式範圍內為限
注意,轉交必須在回應被送出以前完成才會被建立
沒有留言:
張貼留言