2014-11-24 7 views
5

LoggerProducer.java è una classe usata per la produzione di registratori da iniettare in grani CDI con:Perché @Singleton su @ApplicationScoped in Producers?

@Inject 
Logger LOG; 

codice completo:

import javax.ejb.Singleton; 

/** 
* @author rveldpau 
*/ 
@Singleton 
public class LoggerProducer { 

    private Map<String, Logger> loggers = new HashMap<>(); 

    @Produces 
    public Logger getProducer(InjectionPoint ip) { 
     String key = getKeyFromIp(ip); 
     if (!loggers.containsKey(key)) { 
      loggers.put(key, Logger.getLogger(key)); 
     } 
     return loggers.get(key); 
    } 

    private String getKeyFromIp(InjectionPoint ip) { 
     return ip.getMember().getDeclaringClass().getCanonicalName(); 
    } 
} 

DOMANDA: può @Singleton essere girato in modo sicuro in @ApplicationScoped?

Voglio dire, perché qualcuno dovrebbe voler un EJB qui? Ci sono motivi tecnici, dal momento che non sono coinvolte transazioni e (AFAIK) sarebbe comunque thread-safe?

Mi riferisco ovviamente a javax.enterprise.context.ApplicationScoped, non a javax.faces.bean.ApplicationScoped.

+0

HashMap non è disponibile threadsafe –

+0

@SME_Dev ovviamente, il mio errore stava pensando che '@ ApplicationScoped' è, grazie per il commento BTW –

+0

@AndreaLigios puoi chiarire se la tua domanda riguarda' javax.ejb.Singleton' o 'javax.inject.Singleton'? –

risposta

12

L'annotazione fornisce non solo la transazione ma anche la sicurezza del thread per impostazione predefinita. Quindi, se lo sostituirai con @ApplicationScoped, perderai la sincronizzazione. Quindi, al fine di rendere in modo corretto è necessario fare in questo modo:

@ApplicationScoped 
public class LoggerProducer { 

    private final ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<>(); 

    @Produces 
    public Logger getProducer(InjectionPoint ip) { 
     String key = getKeyFromIp(ip); 
     loggers.putIfAbsent(key, Logger.getLogger(key)); 
     return loggers.get(key); 
    } 

    private String getKeyFromIp(InjectionPoint ip) { 
    return ip.getMember().getDeclaringClass().getCanonicalName(); 
    } 
} 

Inoltre è possibile renderlo completamente, senza alcuna possibilità se si effettua la mappa come static

+1

cristallino. Ho erroneamente ricordato che '@ ApplicationScoped' è thread-safe, il che risulta essere sbagliato. Pensandoci su, è assolutamente coerente: tutti gli EJB sono thread-safe, tutti i bean CDI non lo sono, fatta eccezione per questo scope. Grazie per la risposta –

+0

correlati: http://stackoverflow.com/a/14258257/1654265 –