在 CDI 中生成可选 Bean
Produce Optional Beans in CDI
我想在一个方法上使用 @Produces
注释创建一个 CDI 工厂,以便在外部服务中查找命名的东西,并 return(生成)这个东西的代理外部服务被注入到其他 bean 中。从用例的角度来看,通常需要所有这些依赖项;然而,有时远程服务中不存在所请求的内容,应用程序可以对此做出反应。
基本上结构是这样的:
@Singleton public class SomeBean {
@Inject @MyName("required") private Something requiredSomething;
@Inject @MyName("optional") private Instance<Something> optionalSomething;
@PostConstruct void init() {
if (optionalSomething.isUnSatisfied()) {
// act without optional Something in external service
} else {
optionalSomething.get().doWhatIWant(NOW);
}
}
}
@ApplicationScoped
public class SomethingFactory {
@Inject private RemoteSomethingService remoteService;
@Produces
@MyName(value = "")
public Something createRemoteSomething(InjectionPoint injectionPoint) {
MyName name = injectionPoint.getAnnotated().getAnnotation(MyName.class);
Something some = remoteService.lookup(name.value()); // throws an exception if lookup fails
return some;
}
}
这在需要使用某些东西的一侧进行注入的情况下有效:成功的查找会注入查找到的 Something
实例,而不成功的查找会破坏 bean 引导。但是,在使用不存在的东西进行可选注入的情况下,它要么因为 Instance.isUnSatisfied()
returns false
而中断。如果我让 createRemoteSomething()
抛出异常,则在调用 optionalSomething.get()
期间会引发此异常;如果我 return null
相反,同一个调用会导致 NPE。
如何使用 CDI 原语实现这一点?谢谢。
你的生产者方法很好(我假设它的 return 类型应该是 Something
)。您正在 @Dependent
范围(默认)中生成 Something
。
@Dependent
范围内的东西可能是 null
。一般来说,没有别的可能。 (CDI 中有一些来自远古时代的剩余位,当时其他示波器可以生成 null
对象,但它们是过去时代的残余。)
所以在你的情况下,当你不能生产你想要的东西时,只需从你的生产者方法中 return null
,但这不是错误情况(否则显然会抛出某种异常) .
然后,在消费方面,您就差不多了。
Instance#isUnsatisfied()
returns true
仅当没有生产者方法(或其他类型的 bean)可以 "make" 所请求的东西时。在你的例子中,是一个生产者方法可以"make"被要求的东西,所以isUnsatisfied()
returnsfalse
,这是正确的。
你所要做的就是改变这个:
optionalSomething.get().doWhatIWant(NOW);
…至:
final Something something = optionalSomething.get();
if (something == null) {
// no such Something, but an expected case
} else {
something.doWhatIWant(NOW);
}
同样,这仅在 Something
在 @Dependent
范围内(而不是 @ApplicationScoped
范围内)才有效,在您的情况下确实如此。
我想在一个方法上使用 @Produces
注释创建一个 CDI 工厂,以便在外部服务中查找命名的东西,并 return(生成)这个东西的代理外部服务被注入到其他 bean 中。从用例的角度来看,通常需要所有这些依赖项;然而,有时远程服务中不存在所请求的内容,应用程序可以对此做出反应。
基本上结构是这样的:
@Singleton public class SomeBean {
@Inject @MyName("required") private Something requiredSomething;
@Inject @MyName("optional") private Instance<Something> optionalSomething;
@PostConstruct void init() {
if (optionalSomething.isUnSatisfied()) {
// act without optional Something in external service
} else {
optionalSomething.get().doWhatIWant(NOW);
}
}
}
@ApplicationScoped
public class SomethingFactory {
@Inject private RemoteSomethingService remoteService;
@Produces
@MyName(value = "")
public Something createRemoteSomething(InjectionPoint injectionPoint) {
MyName name = injectionPoint.getAnnotated().getAnnotation(MyName.class);
Something some = remoteService.lookup(name.value()); // throws an exception if lookup fails
return some;
}
}
这在需要使用某些东西的一侧进行注入的情况下有效:成功的查找会注入查找到的 Something
实例,而不成功的查找会破坏 bean 引导。但是,在使用不存在的东西进行可选注入的情况下,它要么因为 Instance.isUnSatisfied()
returns false
而中断。如果我让 createRemoteSomething()
抛出异常,则在调用 optionalSomething.get()
期间会引发此异常;如果我 return null
相反,同一个调用会导致 NPE。
如何使用 CDI 原语实现这一点?谢谢。
你的生产者方法很好(我假设它的 return 类型应该是 Something
)。您正在 @Dependent
范围(默认)中生成 Something
。
@Dependent
范围内的东西可能是 null
。一般来说,没有别的可能。 (CDI 中有一些来自远古时代的剩余位,当时其他示波器可以生成 null
对象,但它们是过去时代的残余。)
所以在你的情况下,当你不能生产你想要的东西时,只需从你的生产者方法中 return null
,但这不是错误情况(否则显然会抛出某种异常) .
然后,在消费方面,您就差不多了。
Instance#isUnsatisfied()
returns true
仅当没有生产者方法(或其他类型的 bean)可以 "make" 所请求的东西时。在你的例子中,是一个生产者方法可以"make"被要求的东西,所以isUnsatisfied()
returnsfalse
,这是正确的。
你所要做的就是改变这个:
optionalSomething.get().doWhatIWant(NOW);
…至:
final Something something = optionalSomething.get();
if (something == null) {
// no such Something, but an expected case
} else {
something.doWhatIWant(NOW);
}
同样,这仅在 Something
在 @Dependent
范围内(而不是 @ApplicationScoped
范围内)才有效,在您的情况下确实如此。