根据 Java EE 中的配置注入服务



>我的应用程序当前使用一个类,其中两个服务注入了@Inject注释。

@Stateless
public class MyClass {
@Inject
private SomeService someService;
@Inject
private OtherService otherService;
}

这两种服务非常相似,并且都扩展了抽象Service类。

这是我正在尝试做的...

我的基本想法是MyClass类看起来像这样:

@Stateless
public class MyClass {
@Inject
private Service service;
}

根据配置,应用程序决定注入SomeServiceOtherService

例:

if (config.getValue().equals("some_service")) {
return new SomeService();
} else if (config.getValue().equals("other_service")) {
return new OtherService();
}

Jave EE是否为此提供了解决方案?

要使这项工作,您需要确保任何"制造"SomeService从它可以创建的类型列表中消除Service,以及任何"制造"OtherService它可以创建的类型列表中消除Service

例如,如果SomeService是一个简单的受管 Bean,则需要向其添加@Typed(SomeService.class)注释:

@Typed(SomeService.class)
public class SomeService extends Service {
}

另一方面,如果SomeService是由生产者方法生成的,则必须类似地执行相同的操作:

@Produces
@ApplicationScoped
@Typed(SomeService.class)
private SomeService makeSomeService() {
return fabricateSomeService();
}

@Typed注释将类型集限制为给定的任何内容,而不是推断的内容。

如果您在两个"具体"服务上都执行此操作,那么您在上面的答案中编写的getService()生产者方法应该可以工作。

你的意思是:"取决于配置..."您何时决定使用什么?在编译时还是运行时?

有几种方法可以完成此操作:

1.@Alternative豆.xml

用@Alternative注释某些服务和其他服务,并在 bean 中再次激活其中一个.xml

<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>
<class>SomeService</class>
</alternatives>
</beans>

2. 与限定符和生产者:

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface First {}

并用以下方法注释两个 Beans:

@First
@Stateless
public SomeService{ ...  }

现在,您可以拥有一个如下所示的生产者类:

@Dependent
public class ServiceProducer {
@Inject
@First
private Service someService;
@Inject
@Second
private Service otherService;
@Produces
@Default
public Service getService() {
switch (someCondition) {
case SOME:
return someService;
case OTHER:
return otherService;
default:
return null;
}
}   
}

最后将服务注入到您想要使用它的位置:

@Inject
Service service;

3. 没有生产者,但有限定符注释

您需要注释某些服务和其他服务才能使其正常工作。

@Inject
Instance<Service> services;
public void someBussinessMethod(){
Annotation qualifier = someCondition ? new AnnotationLiteral<First>() {} : new AnnotationLiteral<Second>() {};
Service s = services.select(qualifier).get();
}

4. 不带限定符

在我看来,这是最丑陋和最慢的解决方案,但您可以迭代 Injectend 服务并由类决定是否要使用它。

@Inject
Instance<Service> services;

public void doSomething() {
Class clazz = someCondition ? SomeService.class : OtherService.class;
Service first = services.stream().filter(s -> s.getClass() == clazz).findFirst().get();

}

详细的说明可以在这里找到: https://docs.jboss.org/cdi/learn/userguide/CDI-user-guide.html#injection

关于@kukeltje的评论,我使用了这样的@Produces注释:

@ApplicationScoped
public class MyProducer {
@Inject
private SomeService someService;
@Inject
private OtherService otherService;
@Produces
@ApplicationScoped
public Service getService() {
switch (someCondition) {
case SOME:
return someService;
case OTHER:
return otherService;
default:
return null;
}
}   
}

用法:

@Stateless
public class MyClass {
@Inject
private Service service;
}

最新更新