2012-12-28 10 views
5

Penso di aver capito come funziona il CDI e per immergermi in profondità, mi piacerebbe provare ad usarlo con un esempio di mondo reale. Sono bloccato con una cosa in cui ho bisogno del tuo aiuto per farmi capire. Gradirei davvero il tuo aiuto in questo senso.Il metodo CDI @Producer può assumere parametri personalizzati?

Ho il mio framework del flusso di lavoro sviluppato utilizzando Java reflection API e configurazioni XML dove basato sul tipo specifico di "source" e "eventName" carico la classe Module appropriata e invoco il metodo "process" su quello. Tutto sta funzionando bene nel nostro progetto.

mi sono emozionato con la caratteristica di CDI e voleva dargli provare con la struttura del flusso di lavoro in cui sto progettando iniettare classe modulo invece di caricare utilizzando Riflessione ecc ...

Giusto per darvi un'idea, cercherò per mantenere le cose semplici qui.

"Message.java" è un tipo di oggetto di trasferimento che trasporta "Source" e "eventName", in modo che possiamo caricare il modulo in modo appropriato.

public class Message{ 
private String source; 
private String eventName; 
} 

configurazioni del modulo sono le seguenti

<modules> 
<module> 
    <source>A</source> 
    <eventName>validate</eventName> 
    <moduleClass>ValidatorModule</moduleClass> 
</module> 
<module> 
    <source>B</source> 
    <eventName>generate</eventName> 
    <moduleClass>GeneratorModule</moduleClass> 
</module> 
</modules> 

ModuleLoader.java

public class ModuleLoader { 
public void loadAndProcess(Message message){ 
    String source=message.getSource(); 
    String eventName=message.getEventName(); 

    //Load Module based on above values. 

} 
} 

Domanda

Ora, se voglio implementare stessa via CDI me per iniettare un modulo (nella classe ModuleLoader), posso scrivere in classe Factory con il metodo @Produce, che può farlo. MA la mia domanda è,

a) come può passare oggetto messaggio al metodo @Produce per fare ricerca basata su eventName e origine?

Potete fornire suggerimenti?

Grazie in anticipo.

risposta

4

Questo è un po 'complicato perché CDI non funziona allo stesso modo della soluzione personalizzata (se ho capito bene). CDI deve avere tutto l'elenco di dipendenze e risoluzioni per tali dipendenze al momento dell'avvio, in cui la soluzione sembra trovare tutto in fase di esecuzione in cui le cose possono cambiare. Detto questo, ci sono un paio di cose che potresti provare.

Si potrebbe provare a iniettare un InjectionPoint come parametro per un metodo produttore e restituire l'oggetto corretto o creare il tipo corretto.

C'è anche la creazione di proprio interno di fare questo e la creazione di dipendenze e tutti il ​​cablaggio nel prolungamento (dare un'occhiata a ProcessInjectionTarget, ProcessAnnotatedType, e 'AfterBeanDiscovery` eventi. Questi twoquickstarts può anche aiutare a ottenere alcune idee in corso.

+0

Si noti che il trucco InjectionPoint funziona solo se si @propone un bean con ambito dipendente. Per i bean con valori normali (SessionScoped, ApplicationScoped, RequestScoped, ecc.) Non funzionerà perché si hanno più punti di iniezione e non solo uno solo. – struberg

3

Penso che potresti imbatterti in una strada sbagliata per quanto riguarda un produttore, ma è più che probabile che sarebbe molto meglio utilizzare un osservatore basato soprattutto su ciò che hai descritto.

Sto supponendo che l'oggetto di trasferimento "Messaggio" sia utilizzato in modo astratto come un evento di sistema in cui fondamentalmente si attiva l'evento e si desidera che un gestore definito nel framework XML che è stato creato per determinare il corretto gestore per l'evento, istanziarlo (se necessario), quindi chiamare la classe passandogli l'evento.


@ApplicationScoped 
public class MyMessageObserver { 

    public void handleMessageEvent(@Observes Message message) { 
     //Load Module based on above values and process the event 
    } 
} 

Ora supponiamo che si desidera utilizzare l'interfaccia originale (io immagino che assomiglia):


public interface IMessageHandler { 
    public void handleMessage(final Message message); 
} 

@ApplicationScoped 
public class EventMessageHandler implements IMessageHandler { 

    @Inject 
    private Event<Message> messageEvent; 

    public void handleMessage(Message message) { 
     messageEvent.fire(message); 
    } 
} 

Poi in tutte le fasce eredità si desidera utilizzarlo: @Inject IMessageHandler handler;

Questo ti permetterà di fare tutto ciò che hai descritto.

+1

Grazie per aver mostrato un altro modo. Questo approccio sembra essere promettente. Farò un tentativo. – Raj

2

Può essere necessario somthing così:

  1. È necessario il qualificatore. Annotazione come @Module, che richiederà due sorgenti paramter e eventName; Dovrebbero essere valori non qualificatori. Vedi i documenti.

  2. In secondo luogo è necessario un produttore:

    @Produces 
    @Module 
    public Module makeAmodule(InjectionPoint ip) { 
        // load the module, take source and eventName from ip 
    } 
    
  3. Inject al posto giusto così:

    @Inject 
    @Module(source="A", eventName="validate") 
    Module modulA; 
    

C'è solo un problema con questa soluzione, i moduli devono essere dipendente ambito, altrimenti il ​​sistema inietterà gli stessi moduli di source ed eventName. Se si desidera utilizzare gli ambiti, quindi è necessario fare di origine e eventName parametri qualificati e:

  • fa un estensione per CDI, registro di programmazione produttori
  • o rendere metodo produttore per ciascuno e per ogni possibili combinazioni di sorgente e eventName (Non penso che sia bello)
Problemi correlati