2014-07-18 15 views
9

Non riesco a comprendere l'effettivo ciclo di vita di un bean con scope @Dependent in CDI 1.0 e CDI 1.1. I miei esperimenti finora mi hanno portato alle seguenti conclusioni:Quando viene distrutto un bean CDI con scope @Dependent, se si ottiene quel bean tramite Provider.get()?

  • Un bean con scope non è proxy.
  • No @PreDestroy metodo invocato quando un bean @Dependent viene distrutto.
  • Provider.get() crea sempre una nuova istanza di un bean @Dependent.
  • Con JBoss 6/1.0 CDI, un @Dependent fagiolo che viene creato da un campo @ApplicationScoped bean Provider<> viene "rubato", perché ancora "appartiene" al Provider.
  • Non ho visto alcuna prova (ancora!) Di @Dependent fagioli che sono stati persi da simili Provider s quando si utilizza WELD 2.1.2.Final/CDI 1.1. (Anche se questo potrebbe essere perché questi particolari@Dependent fagioli sono creati da @Produces metodi ...!)

vedo che CDI 1.1 ha aggiunto un metodo destroy() a Instance<>, presumibilmente per affrontare la perdita di memoria in CDI 1.0 . Ma che dire di Provider<> - fa ancora una perdita in CDI 1.1? (E se lo fa, allora come si suppone di utilizzare Provider.get()?)

Fondamentalmente, ho diverse @ApplicationScoped fagioli/@Singleton EJB che I @InjectProvider campi in, e sto provando ad usare Provider.get() come fabbriche per entrambi @Dependent e @RequestScoped fagioli "helper". Io sicuramente non vogliono questi fagioli a "appartengono" ai loro Provider campi, come ho bisogno i fagioli da garbage collection in seguito:

public void updateStuff() { 
    Helper helper = helperProvider.get(); 
    // use helper... 
} 

Per la mia applicazione CDI 1.0, stavo pensando di fissare il perdita di memoria da "falsificare" le mie Provider s con codice come questo:

provider = new Provider<MyBean>() { 
    @Override 
    public MyBean get() { 
     return getReferenceFor(MyBean.class); 
    } 
}; 

private <T> T getReferenceFor(Class<T> type) { 
    Bean<?> bean = beanManager.resolve(beanManager.getBeans(type)); 
    CreationalContext<?> context = beanManager.createCreationalContext(bean); 
    try { 
     return (T) beanManager.getReference(bean, bean.getBeanClass(), context); 
    } finally { 
     // Destroy this context - which I don't want to exist anyway. 
     // I only need a strong reference to a fully @Inject-ed bean! 
     context.release(); 
    } 
} 

MyBean è un @Dependent con scope di fagioli con nessun metodo @PreDestroy che ha solo bisogno di essere garbage collection quando I'v e finito con esso. Tuttavia, non riesco a trovare molte informazioni su Provider s, e quindi non posso dire se sto armando una specie di bomba a tempo facendo questo.

Alcuni dei miei fagioli con ambito @Dependent (che ottengo ancora tramite Provider.get(), btw) sono creati dai metodi @Produces. Sono ancora in pericolo di essere trapelati?

Qualcuno mi può consigliare, per favore?
Grazie,
Chris

+0

Ho anche avuto questo problema. Ho verificato in JVisualVM che tutti i bean dipendenti dal mio bean ApplicationScoped non ricevono mai garbage collection perché dipendono dal bean ApplicationScoped. Ho finito per fare una cosa simile come hai fatto tu. CDI 1.1 risolve questo problema con la classe CDI come ha detto Martin, ma io sono su 1.0 in EE6, quindi ho dovuto usare il BeanManager. – user12722

risposta

1

Da Weld docs sul ciclo di vita dei fagioli @Dependent:

Un'istanza di un fagiolo dipendente è mai condivisa tra diversi clienti o diversi punti di iniezione. È strettamente dipendente dall'oggetto di qualche altro oggetto. Viene istanziato quando l'oggetto a cui appartiene viene creato e distrutto quando l'oggetto a cui appartiene è distrutto.

Quindi l'iniezione dell'oggetto @Dependent non introdurrà una perdita da sola, non c'è semplicemente nulla da risolvere. La creazione di un contesto di breve durata solo "per essere al sicuro" è del tutto inutile perché fagioli dipendenti non sono legati a un contesto. Per quanto riguarda il CDI dopo l'iniezione, sono oggetti Java ordinari (fortemente raggiungibili).
Se hai bisogno di una logica di istanziazione, mettilo in un producer method e il gioco è fatto.

+0

Grazie per la risposta. I miei particolari bean '@ Dependent' sono bean" worker "temporanei piuttosto che campi oggetto. Ad esempio, uno dei miei EJB ha una funzione che fa qualcosa di simile: vuoto updateStuff() { Helper Aiutante = helperProvider.get(); // uso aiutante ...} Questo approccio permette l'aiutante di avere assortiti CDI bontà iniettato in esso, come ad esempio un 'EntityManager' ecc, tuttavia, non ero consapevole che mi perdeva l'oggetto' Helper' seguito ! –

+1

BTW, in base alla [documentazione CDI] (http://docs.jboss.org/cdi/api/1.0-SP1/javax/enterprise/context/Dependent.html): "Un'istanza di un bean con ambito @Dipendente ottenuto mediante invocazione diretta di un'istanza è un oggetto dipendente dell'istanza di un'istanza. " Quindi è leggermente più di un "normale oggetto Java facilmente raggiungibile" - è legato al suo creatore! È questo legame che sto cercando di annullare con il mio codice di soluzione alternativa. –

+0

Basta mettere quella parte del documento dice "Non importa come e dove lo si inietta". @ Dipendente è un oggetto dipendente dal punto di iniezione ". Quindi, a meno che un proprietario del punto di iniezione non sia trapelato, andrà bene. Nella nota a margine, la delega da un bean EJB a un bean CDI è un po 'strana; di solito è il contrario. In questo caso, un bean stateless non sarebbe più adatto di un '@ dependent'? – Yuri

1

Non ho testato il tuo costrutto, ma personalmente, ogni volta che ho bisogno di andare a cercare un bean a livello di codice, preferisco CDI.current().select().get(). Usando questo costrutto, posso confermare che otterrai un nuovo bean @Dependent per ogni ricerca. Non è legato al provider (il contenitore CDI in questo caso).

Vedi this e this. Quello che abbiamo qui è una configurazione di prova Arquillian che distribuire un servlet per un "vero" (o "remoto" utilizzando una terminologia Arquillian) server e problemi di HTTP GET richiesta per scoprire cosa i fagioli sono prodotti al suo interno.

Il risultato è che sia GlassFish 4.1 che WildFly 8.2.0 forniranno il codice client con un nuovo bean @Dependent su ciascuna ricerca e, se ho compreso correttamente la domanda, è esattamente ciò che si desidera. Spero che sia d'aiuto!

Problemi correlati