简体   繁体   中英

Multiple CDI configuration profiles (devel, beta, qa, production) in one war?

Having experience with the Spring DI applicationContext.xml way of declaring Dependency Injection I now try to figure out how to do the same with Java EE6 CDI.

With Spring, I could ship my .jar with several configuration profiles like unittest.xml, devel.xml, qa.xml, production.xml and activate them using command line parameters or environment variables.

With CDI, I could use @Alternative in beans.xml and properties in of web.xml but there seems no way of shipping multiple beans.xml for different environments.

I don't want to use Maven profiles/filters to produce 4-6 versions of my app although I understand that for some scenarios that would be the better solution (ie shipping ready build wars to customers - but I only use my wars internally so let's save compile time!)

Preferably, I would also be able to load those configuration files from the file system so that they could be edited by the sysadmins without having to re-build the app.

What is the Java EE6 way of having multiple configuration sets of dependencies and properties?

If there is none, what are the recommended alternatives as of 2013? Using Spring? Seam? Guice? I saw mentionings of Apache DeltaSpike but they still seem alpha juding from the web page.

I'd use a dynamic producer, using a Qualifier to identify the desired environment

// 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; }
     }

}

So here the container injects all available Greeting implementations into GreetingFactory , which in turn serves as @Producer for the intended one, basing the decision on the system property 'deployenv'.

The above answer by Carlo is good, we have all of this in DeltaSpike with the ProjectStage . Worth taking a look at so you don't have to write it all yourself.

An alternative solution is suggested by M.-Leander Reimer in his presentation Migrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDI (Slide 32), using a CDI extension:

@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();
    }
 }

He uses a custom annotation @ProfileAlternative mimicking Spring's @Profile and a CDI extension observing the ProcessAnnotatedType event to veto() the type if it is annotated with a profile and the profile is not active.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM