2013-02-25 21 views
11

Supponiamo di avere una classe Car. Nel mio codice voglio creare 10 macchine. La classe Car ha alcune dipendenze annotate da @Inject. Quale sarebbe l'approccio migliore per farlo?Come creare istanze al volo in CDI

CDI ha un'interfaccia Provider che posso usare per creare le auto:

@Inject Provider<Car> carProvider; 
public void businessMethod(){ 
    Car car = carProvider.get(); 
} 

Purtroppo questo non funziona se non ho un CarFactory che ha un metodo con @Produces annotazione che crea il auto. Per quanto rifletta il mondo reale che non posso creare auto senza una fabbrica, preferisco non scrivere fabbriche per tutto. Voglio solo che il contenitore CDI crei la mia macchina come qualsiasi altro bean. Come mi consigliate che creo quelle macchine?

risposta

8

Basta usare l'interfaccia javax.enterprise.inject.Instance.

Ti piace questa:

public class Bean { 

    private Instance<Car> carInstances; 

    @Inject 
    Bean(@Any Instance<Car> carInstances){ 
     this.carInstances = carInstances; 
    } 

    public void use(){ 
     Car newCar = carInstances.get(); 
     // Do stuff with car ... 
    } 

} 
+0

Questo è in realtà ciò che ho finito per usare.Puoi correggere il tuo esempio, l'argomento costruttore non è lo stesso tipo dell'attributo class: Car vs UIModule. Inoltre penso che l'iniezione dovrebbe essere annotetade con @New invece di @Any. E un esempio migliore per l'uso() - il metodo sarebbe uno che mostrerebbe come si otterrebbe un'istanza della macchina. Ad esempio 'carInstances.get()' – palto

+0

@New è deprecato in CDI 1.1, preferendo i bean @Dependent. Vedi CDI 1.1, sezione 3.14. Non capisco davvero cosa c'è di sbagliato nell'usare un fornitore, io. e., 'CDI.current(). select (Car.class) .get()'? –

+0

@MartinAndersson Il problema originale era che dovevo creare una fabbrica per l'utilizzo di un provider. L'esempio che hai fornito nel commento è completamente nuovo per me. Forse potresti creare una risposta da questo? – palto

2

Si potrebbe usare qualificatori con i tuoi @Produces annotazioni:

@Qualifier 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER}) 
public @interface MyCars { 
} 

campione-produttore-metodo:

@Produces 
@MyCars 
public Car getNewCar(@New Car car){ 
    return car; 
} 

utilizzo:

@Inject 
@MyCars 
private Provider<Car> carProvider; 
+0

'@New è deprecato in CDI 1.1, preferendo i bean @Dependent. Vedi CDI 1.1, sezione 3.14. –

+0

@MartinAndersson lo so, ma come il tempo della risposta CDI 1.1 non era fuori, quindi la risposta va a CDI 1.0 (solo per chiarire questo qui) – FibreFoX

0

Un altro modo per farlo sarebbe per non dare a Car alcun ambito CDI, che lo rende dipendente e riceverai una nuova istanza ogni volta che viene iniettato e t le istanze del tubo flessibile non verranno distrutte finché l'istanza contenente non viene distrutta.

+0

lo scopo non è qualcosa di cui preoccuparsi, per quanto mi riguarda capito è che voleva avere un produttore iniettato e non dover implementare una specifica classe di produttori. Hai ragione, tutti i cdi-bean iniettati diventano '@ dependent', ma non è quello che palto stava parlando di – FibreFoX

+0

" una nuova istanza ogni volta che viene iniettata "? Come si può iniettare un dipendente "ogni volta"? L'iniezione avviene solo una volta. Di un proxy. Se è stato iniettato un bean @Dependent o un proxy, ogni chiamata a questo proxy verrà sempre instradata a uno stesso bean di supporto. –

+0

Inietta il proxy una volta, sì, ma se quel proxy si risolve in un bean con scope dipendente, quel bean con scope dipendente viene creato nuovo su ogni nuova istanza di bean che richiede l'iniezione. Il fagiolo iniettato diventa dipendente dal ciclo di vita dell'altro. – LightGuard

5

Il mio modello preferito per la ricerca programmatica è quello di utilizzare CDI.current().select().get().

Dimostrato here.

Il servlet ha una dipendenza due chicchi di CDI, una richiesta di ambito e l'altra applicazione ambito:

private final RequestScopedBean requestScoped 
      = CDI.current().select(RequestScopedBean.class).get(); 

private final ApplicationScopedBean applicationScoped 
      = CDI.current().select(ApplicationScopedBean.class).get(); 

La classe di test che utilizza questa servlet può essere trovato here.

Esaminare il codice e si noterà che il codice è completamente equivalente a quello che si otterrebbe utilizzando @Inject MyBean myBean;.