簡體   English   中英

Web應用程序:使用單例模式的servlet線程安全

[英]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實例被重用。

SingletonApplicationScoped對象在整個應用程序中將只有一個副本。 如果要確保該對象只有一個實例,請使用@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM