簡體   English   中英

使用類加載器破解單例-Java Web應用中的Multiton

[英]Hacking a singleton with classloaders - Multiton in a Java web app

我正在使用包含幾個單例類的現有后端創建Web前端。 通過將用戶對象傳遞給DataStore來初始化DataStore,這在桌面應用程序環境中很好,在桌面環境中,該應用程序在每台計算機上啟動一次,但是在旨在滿足多個用戶的服務器端應用程序中無法使用。

數據庫專家不願更改服務層並刪除這些單例以允許每個用戶一個實例,或允許一個服務層對象的單個實例為多個用戶提供服務。 這是有充分的理由的,桌面應用程序已經使用了10年,更改可能會對桌面應用程序產生嚴重的副作用。

我被要求調查使用類加載器來創建單例的多個實例。 我對這個想法一點都不滿意,黑客單身似乎是一種不好的做法,但是更改服務層可能需要花費數月的時間。

我已經通過將我的應用程序的兩個相同的WAR文件(具有不同的文件名)放入Tomcat中進行了測試。 Tomcat為每個Web應用程序都創建了一個類加載器,它們分別工作正常。 我僅在單例使用System.setProperty / System.getProperty時遇到問題,這是可以預期的,因為System類來自樹中更高的類加載器。

為了在單個web應用程序中實現這種分離,它開始變得有點復雜。 似乎我必須為每個會話創建一個不同的類加載器,並使用該類加載器加載整個服務層中的所有類或僅加載單例及其依賴項的類。

當我正在考慮如何在Servlet的會話中使用這些對象時,就會出現問題。 因為每個Servlet在Tomcat中都有一個實例,所以從會話中獲取對象並強制轉換對象並不是一件容易的事。 例如,要從會話中獲取DataStore對象,我將必須將其強制轉換為由正確的ClassLoader加載的正確的DataStore類,因為由兩個不同的ClassLoader加載的單個類算作兩個完全獨立的類。

我已經讀到,如果不小心使用ClassLoader,可能會導致各種各樣的內存泄漏問題。從聲音上看,如果我有500個用戶,則是很多類加載器和類加載器加載的類。 然后,我會不會對PermGen遇到問題?

我想從這個大的解釋中,我確實有四個問題:

  1. 在Web應用程序中使用類加載器入侵單例。 創建潛在的數百個相同類的實例,這些實例被設計為單例。 那是一個可怕的主意嗎? 太可怕了,我不應該考慮嗎?
  2. 如果我絕對必須這樣做,最好的方法是什么?
  3. 如果要獲取對象並將其設置為會話,如何滿足Servlet的轉換要求?
  4. 我最終會遇到內存泄漏和PermGen空間的問題嗎?

我真的很感謝任何建議。 謝謝 :)

  1. 這不是理想的,但我認為這並不可怕。 實際上,它並沒有加載相同類的多個版本(甚至沒有單例)一樣糟糕,並且在復雜的應用程序服務器環境中,尤其是在具有OSGi的環境中,這種情況變得越來越普遍。

  2. 很難說哪種方法最好,但是首先,我將從創建Web應用程序類加載器的子類加載器開始。 安排將實現類加載到子類加載器(即具有單例的加載器)中,並可能使實現類實現從Web應用程序類加載器加載的接口。

  3. 通過從Web應用程序類加載器加載接口。 這基本上與應用程序服務器本身用來調用HttpServlet的方法相同:接口由服務器加載,因此它可以直接引用它,但是實現是在應用程序的子類加載器中進行的。 您只是為了自己的方便而創建了第二層接口/ Impl拆分。

  4. 如果將對子類加載器(或其加載的類,或這些類中的實例化對象)的引用存儲在“父”類加載器中(例如,如果單例注冊了一個MBean,則導致其泄漏),最終將導致內存泄漏。以在JVM范圍的對象中被引用),但這與您沒有創建子類加載器的情況沒有什么不同。 如果要動態創建/銷毀這些單例(因此是子類加載器),則必須注意不要將對這些子類加載器(或類/對象)的引用保留的時間不要超過必需的時間。 PermGen可能存在更多問題。 如果您可以使用Java 8來運行,那就已經不復存在了。 否則,您可能必須增加默認的PermGen大小,具體取決於您需要創建多少個此類裝入器/單個裝入器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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