[英]Web applications: servlet thread safety using singleton pattern
我希望有一個使用Java的Web應用程序編程的經驗,這種編程來自PHP / Laravel背景(大約8年前,我在大學學習過Java的經驗)。
我玩了一段時間,對大多數基本概念(如Servlet和Servlet容器)以及一些流行的Web服務器/ Servlet容器技術(如Jetty,Tomcat等)感到很滿意。我也嘗試過對Java EE進行了大量研究。
現在,由於我想積累有關該主題的知識,因此我不想使用任何框架,實際上,我希望構建自己的學習練習。 但是,我也對周圍的一些框架進行了很多研究,例如Spring MVC,Struts,Play和Vaadin等。
因此,我已經建立了一個Maven項目,已經建立了一個web.xml
文件,該文件指向我創建的servlet,並且我希望在我的“框架”中建立一個入口點。
src / main / webapp / WEB-INF / web.xml
<servlet>
<servlet-name>Application</servlet-name>
<servlet-class>com.mypackage.Application</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
src / main / java / com / mypackage / Application.java
package com.mypackage;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Application extends HttpServlet {
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//
}
}
因此,現在我想制作一個使用單例模式的我自己的IoC容器(我通常不鼓勵這樣做,並且將其視為反模式),因此可以從應用程序的其他部分輕松訪問它:
src / main / java / com / mypackage / Container.java
package com.mypackage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Container {
private static Container instance;
public static Container make(HttpServletRequest request, HttpServletResponse response) {
return instance = new Container();
}
public static Container getInstance() {
if (instance == null) {
// Throw an exception
}
return instance;
}
private Container(HttpServletRequest request, HttpServletResponse response) {
// ...
}
}
我想為每個請求/響應周期(或每個servlet)創建一個Container對象,作為我應用程序的入口點。 所以我想做這樣的事情:
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Container container = Container.make(request, response);
// Do stuff with container and eventually respond to the client
}
現在,我知道線程安全是涉及servlet的一個問題,並且servlet實例上的屬性在線程之間共享,但是我的問題特別涉及我正在使用單例模式和線程安全性創建的Container對象。
我當前的方法是否被認為是線程安全的? 如果沒有,為什么?如何使它線程安全? 請記住,實際上並不想在每個線程之間共享我的Container實例,而是希望為每個傳入的請求/響應提供一個單獨的容器。
在Servlet類的service
方法內創建一個新對象,然后讓該新對象創建Container的實例是線程安全的(或推薦的方法)嗎? 例如
public class Something {
public Something(HttpServletRequest request, HttpServletResponse response) {
Container.make(request, response);
}
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Something something = new Something(request, response);
// Do stuff with container and eventually respond to the client
}
最后,假設線程安全問題是由於servlet容器重用servlet實例而引起的,我是否正確? 根據Java EE文檔 :
Servlet的生命周期由已部署Servlet的容器控制。 當請求映射到servlet時,容器執行以下步驟。
如果servlet的實例不存在,則Web容器
加載servlet類。
創建servlet類的實例。
通過調用init方法初始化servlet實例。 初始化包含在初始化Servlet中。
在servlet中創建實例意味着它不是線程安全的,因為servlet實例被重用。
Singleton
或ApplicationScoped
對象在整個應用程序中將只有一個副本。 如果要確保該對象只有一個實例,請使用@ApplicationScoped
對該類進行注釋:
@ApplicationScoped
public class Something {
//do stuff
}
然后在servlet中注入它:
public class SomeServlet extends HttpServlet {
@Inject
Something obj;
@Override
public void service(HttpServletRequest request, HttpServletResponse response) {
//do stuff
}
}
相反,如果您希望每個請求使用的類是唯一的,則使您的類成為RequestScoped
。 像這樣:
@RequestScoped
public class Something {
//do stuff
}
有關更多信息,請參見https://docs.oracle.com/javaee/6/tutorial/doc/giwhl.html上的CDI教程。 請注意,這將需要使用具有CDI的應用程序服務器,即Payara,而不僅僅是servlet容器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.