首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >禁用@Alternative类

禁用@Alternative类
EN

Stack Overflow用户
提问于 2017-02-15 21:22:51
回答 3查看 1.2K关注 0票数 1

在我的JavaEE7程序中,我想使用@Alternative注入不同的实现,例如,根据上下文、生产或测试。我所做的就是在beans.xml文件中声明用@Alternative注释的类。它工作得很好,我的替代类被注入到我想要的任何地方,而不是默认的那个。但是,除了删除beans.xml文件中的声明之外,我不知道是否有其他方法可以跳过此行为并注入默认类。当应用程序被打包时,这是不可能的。如果我可以选择是在配置文件中使用默认类还是备用类,那就太好了,例如在我的WildFly服务器的standalone.xml文件中。这个是可能的吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-02-21 21:08:32

在我看来,最简单的解决方案是创建一个maven配置文件,就像一些评论中提到的那样。

在我的pom.xml文件中,我添加了一个资源筛选部分和一个配置文件:

代码语言:javascript
复制
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*.*</include>
            </includes>
       </resource>
   </resources>
</build>

<profiles>
    <profile>
        <id>default</id>
        <properties>
            <MyBean></MyBean>
        </properties>
    </profile>
    <profile>
        <id>alternative</id>
        <properties>
            <MyBean><![CDATA[<class>com.MyBean</class>]]></MyBean>
        </properties>
    </profile>
</profiles>

beans.xml文件现在是这样的:

代码语言:javascript
复制
<beans ...>
    <alternatives>
        ${MyBean}
    </alternatives>
</beans>

最后,我只需要使用有用的配置文件mvn package -P alternative执行maven命令。

票数 1
EN

Stack Overflow用户

发布于 2017-02-15 23:03:33

我担心这不可能用普通的@Alternative注解来实现。下面是几种你可以尝试的方法:

使用不同的beans.xml文件

您可以考虑为每个环境使用不同的beans.xml文件,然后根据例如Maven profile打包正确的文件。

编写您自己的替代构造型

您可以定义自己的替代构造型,并使用CDI扩展来管理注入。

NightSpawN的这篇post中提到了这种方法。我在WildFly 10上测试了它,它像预期的那样工作。找到以下步骤:

使用您的环境类型定义枚举:

代码语言:javascript
复制
public enum EnvironmentType {
    DEVELOPMENT, TESTING, STAGING, PRODUCTION;
}

创建您自己的@Alternative构造型来保存关于环境的元信息:

代码语言:javascript
复制
@Stereotype
@Alternative
@Target(TYPE)
@Retention(RUNTIME)
public @interface EnvironmentAlternative  {
    EnvironmentType[] value();
}

并在beans.xml中声明替代构造型

代码语言:javascript
复制
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <alternatives>
        <stereotype>com.example.EnvironmentAlternative</stereotype>
    </alternatives>

</beans>

出于示例目的,让我们定义一个示例服务:

代码语言:javascript
复制
public interface GreetingService {
    String sayGreeting();
}

定义默认实现:

代码语言:javascript
复制
@Default
public class DefaultGreetingService implements GreetingService {

    @Override
    public String sayGreeting() {
        return "Hey!";
    }
}

还要定义一些使用@EnvironmentAlternative构造型的替代实现:

代码语言:javascript
复制
@EnvironmentAlternative(DEVELOPMENT)
public class DevelopmentGreetingService implements GreetingService {

    @Override
    public String sayGreeting() {
        return "Hey from a development environment!";
    }
}
代码语言:javascript
复制
@EnvironmentAlternative(PRODUCTION)
public class ProductionGreetingService implements GreetingService {

    @Override
    public String sayGreeting() {
        return "Hey from a production environment!";
    }
}

@EnvironmentAlternative注释还支持具有多种环境类型的数组:

代码语言:javascript
复制
@EnvironmentAlternative({ TESTING, STAGING })

这就是魔术发生的地方!

创建一个CDI Extension来观察CDI生命周期事件。容器处理的每个带注释的类型都会调用processAnotated()方法,如果它是用@EnvironmentAlternative注释的,并且当前环境不在指定的环境中,则会调用event的veto()方法,从而阻止进一步处理该类型:

代码语言:javascript
复制
public class EnvironmentAlternativesExtension implements Extension {

    private EnvironmentType currentEnvironment = PRODUCTION;

    public <T> void processAnotated(@Observes ProcessAnnotatedType<T> event) {
        EnvironmentAlternative alternative = 
            event.getAnnotatedType().getJavaClass()
                 .getAnnotation(EnvironmentAlternative.class);
        if (alternative != null && !containsCurrentEnvironment(alternative.value())) {
            event.veto();
        }
    }

    private boolean containsCurrentEnvironment(EnvironmentType[] environments) {
        for (EnvironmentType environment : environments) {
            if (environment == currentEnvironment) {
                return true;
            }
        }
        return false;
    }
}

当找不到合适的替代方案时,将使用默认实现。

接下来,通过在META-INF/services文件夹下创建一个名为javax.enterprise.inject.spi.Extension的文件,将CDI扩展注册为服务提供者。文件的内容将是extension类的规范名称:

代码语言:javascript
复制
com.example.EnvironmentAlternativesExtension

最后,注入并使用上面定义的服务:

代码语言:javascript
复制
@Inject
private GreetingService service;
代码语言:javascript
复制
String greeting = service.sayGreeting();

在实际的应用程序中,您不会对currentEnvironment字段的值进行硬编码。例如,您可以使用系统属性来确定应用程序运行的环境。

要在standalone.xml中设置系统属性,请使用<server>标记下的<system-properties>标记:

代码语言:javascript
复制
<server xmlns="urn:jboss:domain:4.2">

    ...

    <system-properties>
        <property name="environment" value="PRODUCTION"/>
    </system-properties>

    ...

</server>

然后使用以下代码获取environemnt变量的值并设置currentEnvironment字段的值:

代码语言:javascript
复制
String environment = System.getProperty("environment");
currentEnvironment = EnvironmentType.valueOf(environment);
票数 2
EN

Stack Overflow用户

发布于 2017-02-16 00:29:31

详细说明我的评论,您可以执行以下操作。

定义单个限定符

代码语言:javascript
复制
@Inherited
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER})
public @interface BeanSelector {

    @NonBinding
    private String environment;

}

定义注解文字

代码语言:javascript
复制
public class BeanSelectorImpl extends AnnotationLiteral<BeanSelector> implements BeanSelector {

    private final String environment;

    public BeanSelectorImpl(final String environment) {
        this.environment = environment;
    }

    public String environment() {
        return this.environment;
    }
}

创建一个从环境中读取数据的生产者

代码语言:javascript
复制
@ApplicationScoped
public class BeanSelectorProducer {

   @Any
   @Inject
   private Instance<MyBeanService> myBeanServices;

   @Produces
   @BeanSelector(environment = "")
   public MyBeanService produceService() {
      final String env = System.getProperty("env.property");
      final BeanSelector beanSelector = new BeanSelectorImpl(env);

      //You may wish to handle exceptions.
      return myBeanServices.select(beanSelector).get();
   }
}

此实现的缺点是所有bean都将处于服务状态。为每个环境定义不同的beans.xml的另一种选择可能是更好的选择。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42250622

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档