Dependency injection 多态性:是否可以基于在@PostConstruct期间初始化的字段将bean B的实现注入bean a?
在我的JSF应用程序中,我使用Dependency injection 多态性:是否可以基于在@PostConstruct期间初始化的字段将bean B的实现注入bean a?,dependency-injection,cdi,Dependency Injection,Cdi,在我的JSF应用程序中,我使用@ViewScopedbeanPublication来显示/编辑来自数据库的数据。在这个bean中,有一个特定于子类型的数据对象的字段,也就是说,根据出版物是(比如)一本书还是一篇文章,包含一个不同的对象 @ViewScoped @Named public class Publication implements Serializable { @Inject DatabaseStorage storage; ... String
@ViewScoped
beanPublication
来显示/编辑来自数据库的数据。在这个bean中,有一个特定于子类型的数据对象的字段,也就是说,根据出版物是(比如)一本书还是一篇文章,包含一个不同的对象
@ViewScoped
@Named
public class Publication implements Serializable {
@Inject
DatabaseStorage storage;
...
String id;
String type;
PublicationType typedStuff;
@PostConstruct
public void init() {
// Get an URL parameter from the request,
// look up row in database accordingly, initialize String "type".
switch (type) {
case "ARTICLE":
typedStuff = new Article(id);
break;
case "BOOK":
typedStuff = new Book(id);
break;
default:
break;
}
}
}
…使用类Article
和Book
实现/扩展PublicationType
到目前为止还不错,但是我希望typedStuff
成为CDIBean,这样我就可以在那里注入有用的资源。
我已经阅读并翻页了producer方法,以及and,但是没有一个方法能够准确地回答我的问题:我可以基于注入bean本身在运行时才知道的字段进行注入吗
我已经让producer方法正常工作了,但是我不能参数化它,所以我不能让开关
正常工作
- 如果我将producer方法放在一个单独的类(或bean)中,那么我就不能访问
字段type
- 如果我将注入bean注入到producer类中,或者将producer方法移动到注入类中,就会得到循环注入
- 如果我将producer方法静态地放入injection类中,我也没有访问权限,因为
不能是静态的。(虽然,因为它只是暂时使用…?)type
- 另外(这可能就是答案所在),producer方法是在注入bean的init方法之前执行的,所以
甚至还没有设置type
有人有更好的主意吗?没有,您不能,但可以根据字段值选择一个bean。说:
public interface PublicationType {}
@PType("ARTICLE")
public class Article implements PublicationType{}
@PType("BOOK")
public class Book implements PublicationType {}
并定义一个限定符:
public @interface PType {
String value();
}
并定义一个注释文字:
public class PTypeLiteral extends AnnotationLiteral<PType> implements PType {}
公共类PTypeLiteral扩展AnnotationLiteral实现PType{}
然后您可以使用:
public class Publication {
@Any
@Inject
private Instance<PublicationType> publicationTypes;
public void doSomething() {
PType ptype = new PTypeLiteral(type);
// Of course you will have to handle all the kind of exceptions here.
PublicationType publicationType = publicationTypes.select(ptype).get();
}
}
公共类发布{
@任何
@注入
私有实例发布类型;
公共无效剂量测定法(){
PType PType=新的PTypeLiteral(类型);
//当然,您必须在这里处理所有类型的异常。
PublicationType PublicationType=publicationTypes.select(ptype.get();
}
}
有javax.inject.Provider
接口(我认为您使用的是同一个包中的@Named
和@inject
注释)
你可以用它来实现你想要的。它将使用注入的字段为您创建实例
一个缺点是您必须自己设置id
@ViewScoped
@Named
public class Publication implements Serializable {
@Inject
DatabaseStorage storage;
@Inject
Provider<Article> articleProvider;
@Inject
Provider<Book> bookProvider;
String id;
String type;
PublicationType typedStuff;
@PostConstruct
public void init() {
// Get an URL parameter from the request,
// look up row in database accordingly, initialize String "type".
switch (type) {
case "ARTICLE":
typedStuff = articleProvider.get();
typedStuff.setId(id);
break;
case "BOOK":
typedStuff = bookProvider.get();
typedStuff.setId(id);
break;
default:
break;
}
}
}
@ViewScoped
@命名
公共类发布实现了可序列化{
@注入
数据库存储;
@注入
提供者和提供者;
@注入
图书供应商;
字符串id;
字符串类型;
PublicationType-typedStuff;
@施工后
公共void init(){
//从请求中获取URL参数,
//相应地在数据库中查找行,初始化字符串“type”。
开关(类型){
案例“第条”:
typedStuff=articleProvider.get();
typedStuff.setId(id);
打破
案例“书”:
typedStuff=bookProvider.get();
typedStuff.setId(id);
打破
违约:
打破
}
}
}
如何获取类型
?你不能用同样的方法得到它吗?另外,CDI是懒惰的,在您使用它生成的bean之前,它不会使用生产者(Weld就是这样做的,您可能正在使用OWB,我不知道它是如何工作的)。如果该场景适合您,那么您的@ViewScoped
bean的init将根据您触摸生产者的类型结束,这意味着它应该可以工作。自己设置id不会有问题。我可以很容易地为构造后调用的init方法切换构造函数。我要试试看@Antares请看一看我回答中的修复,因为我之前写过,提供者是一个注释,而实际上它是一个接口。是的,我直接进入了这个陷阱,谢谢你的纠正。一切都像你说的那样安排好了,一切都完美无缺。不过,它将有很多提供者,因为在现实世界中,我将有十几个(或更多)子类型。我也要看看@maress的答案。好吧,我花了一段时间搜索注释和AnnotationLiteral
的缺失细节,但我最终还是让它工作了(尽管Eclipse抱怨我不应该在实现PType
位中使用注释作为超级接口)。这是一个非常通用的解决方案,我喜欢它。