Что вы пытаетесь достичь, это не выход из функции коробки в CDI, но благодаря SPI и портативному расширению вы можете достичь того, что вам нужно.
Это расширение будет анализировать все точки впрыска с данным типом, получить @Configuration
аннотаций на каждом из них и будет создавать боб в applicationScoped для каждого различного значения члена value()
в аннотации.
Как вы зарегистрировать несколько компонентов с тем же типом вы должны сначала превратить вашу аннотацию в классификаторе
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Configuration {
String value();
}
Ниже класса использовать для создания экземпляров боба:
@Vetoed
public class ConfiguredService {
private String value;
protected ConfiguredService() {
}
public ConfiguredService(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Обратите внимание на аннотацию @Vetoed
, чтобы убедиться, что CDI не возьмет этот класс, чтобы создать компонент, поскольку мы сделаем это сами. Этот класс должен иметь конструктор по умолчанию без параметра, который будет использоваться как класс пассивирующего компонента (в области приложения)
Затем вам нужно объявить класс вашего пользовательского компонента. Видит это как владелец фабрики и метаданных (область действия, квалификаторы и т. Д.) Вашего компонента.
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();
}
}
Обратите внимание, что классификатор является единственным параметром, что позволяет нам связать содержание спецификатора к экземпляру в методе create()
.
Наконец, вы создадите расширение, которое зарегистрирует ваши компоненты из коллекции точек впрыска.
public class ConfigurationExtension implements Extension {
private Set<Configuration> configurations = new HashSet<>();
public void retrieveTypes(@Observes ProcessInjectionPoint<?, ConfiguredService> pip, BeanManager bm) {
InjectionPoint ip = pip.getInjectionPoint();
if (ip.getAnnotated().isAnnotationPresent(Configuration.class))
configurations.add(ip.getAnnotated().getAnnotation(Configuration.class));
else
pip.addDefinitionError(new IllegalStateException("Service should be configured"));
}
public void createBeans(@Observes AfterBeanDiscovery abd, BeanManager bm) {
ConfiguredServiceBean.types = bm.createAnnotatedType(ConfiguredService.class).getTypeClosure();
for (Configuration configuration : configurations) {
abd.addBean(new ConfiguredServiceBean(configuration));
}
}
}
Это расширение активируется путем добавления его полное имя класса в META-INF/services/javax.enterprise.inject.spi.Extension
текстовый файл.
Есть и другой способ создания вашей функции с расширением, но я попытался дать вам код, работающий с CDI 1.0 (кроме аннотации @Vetoed
).
Исходный код этого расширения можно найти в моем CDI Sandbox on Github.
Код довольно прост, но не стесняйтесь, если у вас есть вопросы.