通过非限定符注释对Bean进行范围界定

时间:2019-10-03 21:00:44

标签: java cdi

假设我有一个类RecordSender,其构造函数采用目标名称。为了对这个类进行CDI化,我可能会写一个像这样的生产者,该生产者检查注入点以找到一个名为Topic的注释(不是限定符,因为不能用所有可能的主题名称值来注释生产方法。它可能会产生):

@Produces
public RecordSender getRecordSender(InjectionPoint injectionPoint) {
    return new RecordSender(injectionPoint.getAnnotated().getAnnotation(Topic.class).value());
}

但是,假设这个RecordSender类非常繁重但具有线程安全性,因此应尽可能多地共享。这意味着我希望任何看起来像@Inject @Topic("FooBar") RecordSender fooBarSender的注入站点共享以FooBar为名称构造的RecordSender实例。

我们不能将生产者方法标记为ApplicationScoped,因为RecordSenders只能在具有相同名称的注入点之间共享。我们不能将@Topic设置为限定符,因为此限定符不会注释生产者方法。解决此问题的CDI方法是什么?

我的愿景是添加一个范围注释(可能是ScopedTo),它的参数是一个非限定符注释类,它将强制分离它们所注释的bean的范围。因此,例如,生产者方法上的@ApplicationScoped @ScopedTo(Topic.class)就是我的问题的答案(每个应用程序每个唯一的Topic注释一个RecordSender)

2 个答案:

答案 0 :(得分:0)

另一种方法是编写一个可移植的扩展程序,该扩展程序对相关的注入点进行扫描和分类,然后在观察器AfterBeanDiscovery的观察器方法中,ApplicationScoped范围内的programmatically adds beans相关的注射点类别。这样一来,您就不必在生产者方法中进行动态InjectionPoint选择了。

答案 1 :(得分:0)

最好的方法可能是走扩展路线。

但是,另一种更简单的方法可能是将生产者放在应用程序范围的Bean中。该bean可能包含某种缓存(值较小的映射可能会完成此任务)。这样,如果给定类型已经存在,则可以返回缓存的版本,否则在从生产者返回之前创建新的对象和缓存。该键可以从您的主题注释中提取。如果这是一个限定词,则可以将topic属性标记为非绑定。