2013-02-19 15 views
7

Sto eseguendo un backend Java RESTful su GlassFish. In allegato c'è un frontend HTML5/JS che posso inserire in un progetto webapp (e quindi includere il backend come dipendenza), o girare su un server web IIS in una posizione diversa. CORS non è un problema. Qualunque sia risolve questo problema seguente:ThreadLocal Singleton

Situazione:

  1. Utente1 accede e il percorso del database è impostato su 'db/user1 /'
  2. inserti user1 'Valore 1' nel database
  3. tronchi Utente2 on e il percorso del database è impostato su 'db/user2 /'
  4. Utente1 tenta di eliminare 'valore 1' dal database

Utente1 non sarebbe in grado di eliminare il Valore 1 da db/utente1, poiché il database di dati è stato modificato in db/utente2 e non esiste alcun valore 1 in quel database.

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

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

Come posso modificare il metodo getInstance() in modo che agisce come un singleton, ma solo all'interno del filo di quell'utente? Ho visto qualcosa chiamato threadlocal ma non l'ho capito appieno, forse è una soluzione?

Qualsiasi aiuto è sicuramente apprezzato.

+0

Hai posto 9 domande e accettato 0. Per favore, migliora. – gaborsch

+0

come posso accettare una risposta –

+0

Leggi questo capitolo in FAQ, ci sono anche screenshot: http://stackoverflow.com/faq#howtoask – gaborsch

risposta

9

Si potrebbe utilizzare la classe ThreadLocal in un modello di fabbrica:

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(); 
    } 
} 

Ciò, tuttavia, causare una perdita di memoria. Quindi è necessario utilizzare un Servlet Filter per impostare il valore a inizio di una richiesta e quindi eliminarlo alla fine, un po 'come:

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(); 
     } 
    } 

volta che hai un class che implementa Filter lo si aggiunge al tuo web.xml così :

<!--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 pagina fornisce un esempio di un filtro e le sue mappature.
E il tuo DataAccess sarà simile:

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(); 
    } 
} 

essere estremamente attenti con ThreadLocal in quanto è probabilmente la prima causa di perdite di memoria in Java. Con i server Web che dispongono di pool di thread è possibile ottenere bug ancora più gravi se non vengono puliti correttamente.

+0

+1, volevo solo scrivere lo stesso, ma eri più veloce :) – gaborsch

+1

Il la velocità delle risposte su SO mi ha sempre sorpreso ... –

+2

Si noti che 'ThreadLocal's non funziona se si utilizza qualcosa di speciale, ad es. EJB asincroni, Comets/Continuations, perché sostituiranno il Thread in esecuzione con un altro. – gaborsch