2013-06-03 17 views
9

Avendo esperienza con il metodo Spring application applicationContext.xml di dichiarare Iniezione delle dipendenze, ora provo a capire come fare lo stesso con Java EE6 CDI.Profili di configurazione CDI multipli (devel, beta, qa, produzione) in una guerra?

Con Primavera, ho potuto spedire il mio .jar con diversi profili di configurazione come unittest.xml, devel.xml, qa.xml, production.xml e attivarli utilizzando i parametri della riga di comando o variabili d'ambiente.

Con CDI, ho potuto utilizzare @Alternative in beans.xml e immobili a di web.xml ma non sembra esserci modo di spedizione beans.xml multiplo per ambienti diversi.

Non voglio usare i profili/filtri Maven per produrre 4-6 versioni della mia app, anche se capisco che per alcuni scenari quella sarebbe la soluzione migliore (ad esempio spedizione pronta per costruire guerre ai clienti - ma io uso solo le mie guerre internamente quindi risparmiamo tempo!)

Preferibilmente, sarei anche in grado di caricare quei file di configurazione dal file system in modo che potessero essere modificati dagli amministratori di sistema senza dover ricostruire l'app.

Che cos'è il modo Java EE6 di disporre di più set di configurazioni di dipendenze e proprietà?

Se non ce ne sono, quali sono le alternative consigliate del 2013? Usando la primavera? Cucitura? Guice? Ho visto menzioni di Apache DeltaSpike ma sembrano ancora alfa giudicare dalla pagina web.

+0

Suggerisco di non dare agli amministratori di sistema la possibilità di cambiare tutto. Lascia che cambino un sottoinsieme selezionato. OK. Ma non tutto o un giorno passerai un lungo tempo a fare il debugging di un errore che hanno fatto che non puoi riprodurre. –

risposta

7

userei un produttore dinamico, utilizzando un Qualifier per identificare l'ambiente desiderato

// The qualifier for the production/qa/unit test 
@Qualifier 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE, ElementType.METHOD, 
ElementType.FIELD, ElementType.PARAMETER}) 
public @interface Stage { 
    String value() default "production"; 
} 

// The interface for the stage-dependant service 
public interface Greeting{ 
    public String sayHello(); 
} 

// The production service 
@Stage("production") 
public class ProductionGreeting implements Greeting{ 
    public String sayHello(){return "Hello customer"; } 
} 

// The QA service 
@Stage("qa") 
public class QAGreeting implements Greeting{ 
    public String sayHello(){return "Hello tester"; } 
} 

// The common code wich uses the service 
@Stateless 
public class Salutation{ 
    @Inject Greeting greeting; 
    public String sayHello(){ return greeting.sayHello(); }; 
} 

// The dynamic producer 
public class GreetingFactory{ 
    @Inject 
    @Any 
    Instance<Greeting> greetings;   

    public String getEnvironment(){ 
     return System.getProperty("deployenv"); 
    } 

    @Produces 
    public Greeting getGreeting(){ 
     Instance<Greeting> found=greetings.select(
      new StageQualifier(getEnvironment())); 
     if (!found.isUnsatisfied() && !found.isAmbiguous()){ 
      return found.get(); 
     } 
     throw new RuntimeException("Error ..."); 
    } 

    public static class StageQualifier 
     extends AnnotationLiteral<Stage> 
     implements Stage { 
     private String value; 

     public StageQualifier(String value){ 
      this.value=value; 
     } 
     public String value() { return value; } 
    } 

} 

Quindi, ecco il contenitore inietta tutti Greeting implementazioni disponibili in GreetingFactory, che a sua volta serve come @Producer per il previsto uno, basando la decisione sulla proprietà di sistema 'deployenv'.

+0

Grazie per il codice sorgente di esempio. È un esempio interessante per @Produces, sembra che dovrei scrivere una Factory per ogni classe che esiste in più varianti e che potrebbero essere poche. Sarebbe anche complicato se avessi una dozzina di variabili "@Inject String password" come dovrei usare i qualificatori per differenziare i vari tipi di String. Quindi non sembra scalare per grandi applicazioni, o? – lathspell

+0

Bene, è il prezzo da pagare per digitare safeness ...Inoltre, il qualificatore '@ Stage' potrebbe essere utilizzato per tutti i tipi configurabili, lo stesso si potrebbe dire per' GreetingFactory' che potrebbe produrre tutti i bean iniettabili dinamicamente. Per quanto riguarda '@Inject String password', è possibile introdurre un singolo qualificatore, definendo la proprietà di origine come in' @Inject @Config ("db.password") String password'. Un altro (più drastico) approccio potrebbe essere sfruttando l'API di estensione portatile. –

+0

Come si passa da una fase all'altra del codice? In altre parole, dov'è lo stage definito/configurato e quale file deve essere modificato dal generatore di Maven? –

2

La risposta di sopra di Carlo è buona, abbiamo tutto questo in DeltaSpike with the ProjectStage. Vale la pena dare un'occhiata in modo da non dover scrivere tutto da solo.

+0

L'approccio @ @ Exclude (exceptIf = Development.class) @Alternative_ sembrava promettente, ma spesso fasi di progetto diverse utilizzano la stessa classe ma con proprietà diverse (nome utente/password), come verranno iniettate? La documentazione dice solo "TODO" :) Lo voglio in qualche tipo di file .properties o .xml modificabili esternamente e non come file finali pubblici in una classe Java compilata. Come hai scritto "noi": dovrei aprire un biglietto Jira con una lista dei desideri? :) – lathspell

+0

Sei certamente benvenuto ad aprire un biglietto JIRA, iscriviti al nostro [elenco utenti] [mailto: [email protected]], oppure visitaci su IRC#deltaspike. Quello che stai cercando sarebbe il pezzo di configurazione, lo puoi trovare nella stessa documentazione a cui ti ho collegato in precedenza. – LightGuard

1

Una soluzione alternativa è suggerito da M.-Leander Reimer nella sua presentazione Migrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDI (Far scorrere 32), utilizzando un'estensione CDI:

@Alternative 
@Stereotype 
@Target({ElementType.TYPE, ElementType.METHOD}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface ProfileAlternative { 
    Profile[] value(); 
} 

public void processAnnotated(@Observes ProcessAnnotatedType<?> event) { 
    ProfileAlternative pa = getProfileAlternative(event); 
    if (profileAlternativeIsNotActive(pa)) { 
     event.veto(); 
    } 
} 

egli utilizza un'annotazione personalizzato @ProfileAlternative mimando un'estensione CDI di primavera @Profile e osservando l'evento ProcessAnnotatedType a veto() il tipo se è annotato con un profilo e il profilo non è attivo.