Java 在一场战争中有多个CDI配置文件(devel、beta、qa、production)?

Java 在一场战争中有多个CDI配置文件(devel、beta、qa、production)?,java,spring,java-ee-6,cdi,Java,Spring,Java Ee 6,Cdi,有了使用SpringDI applicationContext.xml声明依赖注入的经验,我现在试图找出如何使用JavaEE6CDI实现同样的功能 使用Spring,我可以将.jar与几个配置文件一起提供,如 并使用命令行参数或环境变量激活它们 有了CDI,我可以在beans.xml中使用@Alternative,在web.xml中使用properties,但似乎没有办法为不同的环境提供多个beans.xml 我不想使用Maven配置文件/过滤器来生成我的应用程序的4-6个版本,尽管我知道在某些

有了使用SpringDI applicationContext.xml声明依赖注入的经验,我现在试图找出如何使用JavaEE6CDI实现同样的功能

使用Spring,我可以将.jar与几个配置文件一起提供,如 并使用命令行参数或环境变量激活它们

有了CDI,我可以在beans.xml中使用@Alternative,在web.xml中使用properties,但似乎没有办法为不同的环境提供多个beans.xml

我不想使用Maven配置文件/过滤器来生成我的应用程序的4-6个版本,尽管我知道在某些情况下,这将是更好的解决方案(即向客户提供现成的构建战争-但我只在内部使用我的战争,所以让我们节省编译时间!)

最好,我还能够从文件系统加载这些配置文件,这样系统管理员就可以编辑它们,而无需重新构建应用程序

JavaEE6拥有多个依赖项和属性配置集的方式是什么


如果没有,截至2013年,推荐的替代方案是什么?使用弹簧?接缝Guice?我看到有人提到ApacheDeltaspike,但从网页上看,它们仍然像是alpha juding。

我会使用动态生产者,使用
限定符来识别所需的环境

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

}
//生产/质量保证/单元测试的限定符
@限定词
@保留(RetentionPolicy.RUNTIME)
@目标({ElementType.TYPE,ElementType.METHOD,
ElementType.FIELD,ElementType.PARAMETER})
公共@接口阶段{
字符串值()默认为“生产”;
}
//阶段相关服务的接口
公共界面问候语{
公共字符串sayHello();
}
//生产服务
@舞台(“制作”)
公共类ProductionGreeting实现问候语{
公共字符串sayHello(){返回“Hello customer”;}
}
//质量保证服务
@阶段(“qa”)
公共类实现问候语{
公共字符串sayHello(){返回“Hello tester”;}
}
//使用该服务的公共代码
@无国籍
公开课敬礼{
@注入问候语;
公共字符串sayHello(){return greeting.sayHello();};
}
//动态生产者
公共类迎宾工厂{
@注入
@任何
实例问候;
公共字符串getEnvironment(){
returnsystem.getProperty(“deployenv”);
}
@产生
公共问候语{
找到实例=问候语。选择(
新的stageequalifier(getEnvironment());
如果(!found.isUnsatisfied()&&!found.isAmbiguous()){
返回find.get();
}
抛出新的运行时异常(“错误…”);
}
公共静态类均衡器
扩展AnnotationLiteral
实施阶段{
私有字符串值;
公共分段均衡器(字符串值){
这个。值=值;
}
公共字符串值(){return value;}
}
}

因此,在这里,容器将所有可用的
问候语
实现注入
问候工厂
,该工厂反过来充当目标工厂的
@Producer
,根据系统属性“deployenv”的决定。

Carlo的上述答案很好,我们在DeltaSpike中有所有这些。值得一看,这样你就不必自己写了。

M.-Leander Reimer在他的演示文稿(幻灯片32)中建议了一种替代解决方案,使用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();
    }
 }
@备选方案
@刻板印象
@目标({ElementType.TYPE,ElementType.METHOD})
@保留(RetentionPolicy.RUNTIME)
public@interface profiler可选{
配置文件[]值();
}
public void processAnnotated(@ProcessAnnotatedType事件){
ProfileAlternative pa=getProfileAlternative(事件);
如果(可选配置文件不活动(pa)){
事件否决权();
}
}

他使用一个自定义注释
@ProfileAlternative
模仿Spring的
@Profile
,并使用一个CDI扩展来观察
ProcessAnnotatedType
事件,以
否决()
该类型,前提是该类型使用了一个配置文件进行注释,并且该配置文件未处于活动状态。

我建议不要给系统管理员更改一切的能力。让他们更改选定的子集。好啊但并不是所有的东西,否则有一天你会花很长时间调试他们犯下的错误,你无法重现。谢谢你的示例源代码。对于@products来说,这是一个有趣的例子,似乎我必须为存在于多个变体中的每个类编写一个工厂,可能只有几个。如果我有一个dozend“@injectstringpassword”变量,它也会变得混乱,因为我必须使用限定符来区分几种字符串类型。因此,它似乎无法扩展到大型应用程序,或者?嗯,这是为类型安全性付出的代价。。。此外,
@Stage
限定符可以用于所有可配置类型,同样可以用于可以生成所有动态注入bean的
GreetingFactory
。对于
@Inject-String-password
,您可以引入一个限定符,在
@Inject-Config(“db.password”)String-password
中定义origin属性。另一种(更激进的)方法是利用可移植扩展API。如何在代码中的各个阶段之间切换?换句话说,stage在哪里定义/配置,maven构建需要更改什么文件?在上面的代码中,它是在
GreetingFactory
中通过方法
getEnvironment()
完成的。在示例中,它是一个简单的系统属性,但在方法中,您可以加载属性文件。@Exclude(exceptIf=Development.class)@替代方法看起来很有希望,但不同的项目阶段通常使用相同的类,但具有不同的属性(用户名/密码),它们将如何被注入?文档中只显示“待办事项”: