2013-02-19 50 views
7

我正在GlassFish上運行RESTful java後端。附加的是一個HTML5/JS前端,我可以將它放在一個webapp項目中(然後將後端作爲依賴包含在內),或者在另一個位置上的IIS web服務器上運行。 CORS不是問題。無論解決了這個以下問題:ThreadLocal Singleton

情況:

  1. 用戶1登錄和數據庫路徑被設置爲 '分貝/ USER1 /'
  2. User1的刀片 '值1' 到數據庫
  3. User2的日誌上和數據庫路徑被設置爲「分貝/用戶2 /」
  4. 用戶1試圖從數據庫

用戶1將不刪除「值1」能夠從db/user1刪除值1,因爲數據庫路徑已更改爲db/user2,並且該數據庫中沒有值1。

public class DataAccess{ 
    private static DataAccess dataaccess; 
    private String databasepath; 

    public static DataAccess getInstance() { 
     if (dataaccess == null) { 
      dataaccess = new DataAccess(); 
     } 
    } 
} 

我如何修改getInstance()方法,使其作爲一個單身,但只有該用戶的線程內?我看到一個名爲threadlocal的東西,但沒有完全理解它,這可能是一個解決方案嗎?

任何幫助是肯定讚賞。

+0

你有9個問題,並接受0.請改善它。 – gaborsch 2013-02-19 14:15:59

+0

我該如何接受答案 – 2013-02-19 14:27:09

+0

閱讀本章常見問題解答,甚至有截圖:http://stackoverflow.com/faq#howtoask – gaborsch 2013-02-19 14:34:07

回答

9

可以使用ThreadLocal類工廠模式:

public class DataAccess{ 
    private static ThreadLocal<DataAccess> THREAD_LOCAL = new ThreadLocal() { 
    @Override 
    protected DataAccess initialValue() { 
      return new DataAccess(); 
    } 
    }; 
    private String databasepath; 

    public static DataAccess getInstance() { 
     return THREAD_LOCAL.get(); 
    } 
} 

然而這將,導致內存泄漏。所以,你需要使用一個Servlet Filter設定值在請求開始,然後在年底將其刪除,有的像:

public void doFilter(ServletRequest request, 
     ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 
     DataAccess.set(new DataAccess("SomeValue")); 
     try { 
     chain.doFilter(request, wrapper); 
     } finally { 
     DataAcess.remove(); 
     } 
    } 

一旦你有一個class實現Filter你把它添加到您的web.xml從而:

<!--Filter for adding in dataccess objects--> 
<filter> 
    <filter-name>DataccessFilter</filter-name> 
    <filter-class>my.package.DataccessFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>DataccessFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

This page給出了一個過濾器及其映射的例子。
和你DataAccess會是什麼樣子:

public class DataAccess{ 
    private static ThreadLocal<DataAccess> THREAD_LOCAL = new ThreadLocal(); 
    private String databasepath; 

    public DataAcess(final String databasepath) { 
     this.databasepath = databasepath; 
    } 

    public static DataAccess getInstance() { 
     return THREAD_LOCAL.get(); 
    } 
    public static void set(final DataAccess dataAccess) { 
     THREAD_LOCAL.set(dataAccess); 
    } 
    public static void remove() { 
     THREAD_LOCAL.remove(); 
    } 
} 

非常小心ThreadLocal,因爲它可能是在Java內存泄漏的頭號原因。使用具有線程池的Web服務器,如果不正確地清理它們,可能會出現更嚴重的錯誤。

+0

+1,我只是想寫一樣的,但你更快:) – gaborsch 2013-02-19 14:08:18

+1

SO的答案速度總是令我驚訝...... – 2013-02-19 14:10:09

+2

請注意,如果使用任何特殊的東西,'ThreadLocal's不起作用,例如異步EJB的Comets/Continuations,因爲它們將用另一個代替正在運行的Thread。 – gaborsch 2013-02-19 14:10:16