Java CDI-已处理但已配置的应用程序

Java CDI-已处理但已配置的应用程序,java,configuration,scope,cdi,code-injection,Java,Configuration,Scope,Cdi,Code Injection,问题 使用CDI,我希望生成@ApplicationScopedbean 此外,我希望为注入点提供配置注释,例如: @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface Configuration { String value(); } 我不想为value的每个不同可能性编写一个单独的生产者

问题

使用CDI,我希望生成
@ApplicationScoped
bean

此外,我希望为注入点提供配置注释,例如:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {

  String value();

}
我不想为
value
的每个不同可能性编写一个单独的生产者


方法

通常的方法是制作生产者并处理注入点注释:

@Produces
public Object create(InjectionPoint injectionPoint) {
    Configuration annotation = injectionPoint.getAnnotated().getAnnotation(Configuration .class);
    ...
}
因此,bean不能再被应用程序限定范围,因为每个注入点可能不同(producer的参数injectionpoint不适用于
@aplicationscope
注释的生产者)

所以这个解决方案不起作用


问题

我需要具有相同值的注入点获得相同bean实例的可能性

是否有一种内置的CDI方式?或者我是否需要在列表中以某种方式“记住”bean,例如在包含生产者的类中


我需要的基本上是针对每个不同的
应用程序实例,您尝试实现的不是CDI中的现成功能,而是由于其SPI和便携扩展,您可以实现您所需的功能

此扩展将分析给定类型的所有注入点,在每个注入点上获取
@Configuration
注释,并将在应用程序中为注释中成员
value()
的每个不同值创建一个bean

由于您将使用同一类型注册多个bean,因此首先必须将注释转换为限定符

@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Configuration {
    String value();
}
在用于创建bean实例的类下面:

@Vetoed
public class ConfiguredService {

    private String value;

    protected ConfiguredService() {
    }

    public ConfiguredService(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}
请注意
@Vetoed
注释,以确保CDI不会像我们自己那样选择这个类来创建bean。这个类必须有一个没有参数的默认构造函数才能用作钝化bean的类(在应用程序范围内)

然后需要声明自定义bean的类。将其视为bean的工厂和元数据持有者(范围、限定符等)

public class ConfiguredServiceBean implements Bean<ConfiguredService>, PassivationCapable {


    static Set<Type> types;
    private final Configuration configuration;
    private final Set<Annotation> qualifiers = new HashSet<>();

    public ConfiguredServiceBean(Configuration configuration) {
        this.configuration = configuration;
        qualifiers.add(configuration);
        qualifiers.add(new AnnotationLiteral<Any>() {
        });
    }

    @Override
    public Class<?> getBeanClass() {
        return ConfiguredService.class;
    }

    @Override
    public Set<InjectionPoint> getInjectionPoints() {
        return Collections.EMPTY_SET;
    }

    @Override
    public boolean isNullable() {
        return false;
    }

    @Override
    public Set<Type> getTypes() {
        return types;
    }

    @Override
    public Set<Annotation> getQualifiers() {
        return qualifiers;
    }

    @Override
    public Class<? extends Annotation> getScope() {
        return ApplicationScoped.class;
    }

    @Override
    public String getName() {
        return null;
    }

    @Override
    public Set<Class<? extends Annotation>> getStereotypes() {
        return Collections.EMPTY_SET;
    }

    @Override
    public boolean isAlternative() {
        return false;
    }

    @Override
    public ConfiguredService create(CreationalContext<ConfiguredService> creationalContext) {
        return new ConfiguredService(configuration.value());
    }

    @Override
    public void destroy(ConfiguredService instance, CreationalContext<ConfiguredService> creationalContext) {
    }

    @Override
    public String getId() {
        return getClass().toString() + configuration.value();
    }
}
通过将其完全限定的类名添加到
META-INF/services/javax.enterprise.inject.spi.extension
文本文件,可以激活此扩展名

有其他方法可以通过扩展创建功能,但我尝试给您一个从CDI 1.0开始工作的代码(除了
@Vetoed
注释)

您可以在my中找到此扩展的源代码


代码非常简单,但如果您有疑问,请不要犹豫。

您尝试实现的不是CDI中的现成功能,而是由于其SPI和可移植扩展,您可以实现所需的功能

此扩展将分析给定类型的所有注入点,在每个注入点上获取
@Configuration
注释,并将在应用程序中为注释中成员
value()
的每个不同值创建一个bean

由于您将使用同一类型注册多个bean,因此首先必须将注释转换为限定符

@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Configuration {
    String value();
}
在用于创建bean实例的类下面:

@Vetoed
public class ConfiguredService {

    private String value;

    protected ConfiguredService() {
    }

    public ConfiguredService(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}
请注意
@Vetoed
注释,以确保CDI不会像我们自己那样选择这个类来创建bean。这个类必须有一个没有参数的默认构造函数才能用作钝化bean的类(在应用程序范围内)

然后需要声明自定义bean的类。将其视为bean的工厂和元数据持有者(范围、限定符等)

public class ConfiguredServiceBean implements Bean<ConfiguredService>, PassivationCapable {


    static Set<Type> types;
    private final Configuration configuration;
    private final Set<Annotation> qualifiers = new HashSet<>();

    public ConfiguredServiceBean(Configuration configuration) {
        this.configuration = configuration;
        qualifiers.add(configuration);
        qualifiers.add(new AnnotationLiteral<Any>() {
        });
    }

    @Override
    public Class<?> getBeanClass() {
        return ConfiguredService.class;
    }

    @Override
    public Set<InjectionPoint> getInjectionPoints() {
        return Collections.EMPTY_SET;
    }

    @Override
    public boolean isNullable() {
        return false;
    }

    @Override
    public Set<Type> getTypes() {
        return types;
    }

    @Override
    public Set<Annotation> getQualifiers() {
        return qualifiers;
    }

    @Override
    public Class<? extends Annotation> getScope() {
        return ApplicationScoped.class;
    }

    @Override
    public String getName() {
        return null;
    }

    @Override
    public Set<Class<? extends Annotation>> getStereotypes() {
        return Collections.EMPTY_SET;
    }

    @Override
    public boolean isAlternative() {
        return false;
    }

    @Override
    public ConfiguredService create(CreationalContext<ConfiguredService> creationalContext) {
        return new ConfiguredService(configuration.value());
    }

    @Override
    public void destroy(ConfiguredService instance, CreationalContext<ConfiguredService> creationalContext) {
    }

    @Override
    public String getId() {
        return getClass().toString() + configuration.value();
    }
}
通过将其完全限定的类名添加到
META-INF/services/javax.enterprise.inject.spi.extension
文本文件,可以激活此扩展名

有其他方法可以通过扩展创建功能,但我尝试给您一个从CDI 1.0开始工作的代码(除了
@Vetoed
注释)

您可以在my中找到此扩展的源代码

代码非常直截了当,但如果您有疑问,请不要犹豫