我试着从Wildfly的Java EE7开发书中了解一个JSF示例,但这里有一些我不理解的东西 - 即使它有效:
豆:
@Named
@RequestScoped
public class TheatreSetupService {
...
@Produces
@Named
private SeatType newSeatType;
@PostConstruct
public void initNewSeatType() {
newSeatType = new SeatType();
}
....
}
XHTML:
<h:form id="reg" role="form">
<div class="form-group has-feedback #{!desc.valid? 'has-error' : ''}">
<h:outputLabel for="desc" value="Description"
styleClass="control-label"/>
<h:inputText id="desc" value="#{newSeatType.description}"
p:placeholder="Enter a description here" class="form-control"
binding="#{desc}"/>
<span class="#{!desc.valid ? 'glyphicon glyphicon-remove form-control-feedback' : ''}"/>
<h:message for="desc" errorClass="control-label has-error"/>
</div>
</h:form>
实体:
@Entity
@Table(name = "seat_type")
public class SeatType implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Size(min = 1, max = 25, message = "Enter a Seat Description (max 25 char)")
@Pattern(regexp = "[A-Za-z ]*", message = "Description must contain only letters and spaces")
private String description;
private SeatPosition position;
@NotNull
private Integer price;
@NotNull
private Integer quantity;
@OneToMany(mappedBy = "seatType", fetch = FetchType.EAGER)
private List<Seat> seats;
public SeatType() {
// empty for jpa
}
...
}
我不理解@Produces对成员变量newSeatType的影响。创建由类TheatreSetupService显然管理。对我来说,它看起来就像导出一样,成员可用于jsf,但@Named注释不足以使这个例子起作用。谁能解释一下这个小例子会发生什么?据我所知,这种情况并不经常使用 - 这是真的吗?
感谢您的任何提示!
星
答案 0 :(得分:1)
这比特定于JSF的CDI更具特异性。
@Named
注释是在CDI中引入的,旨在成为相同类型的不同bean注入的名称识别限定符。它还用于替换使用@ManagedBean
注释的以前的JSF托管bean(如果在没有安装CDI的情况下运行在标准servlet容器上,如Tomcat,@ManagedBean
仍然是唯一的解决方案)。因此,一个注释了@Named
注释的bean是一个CDI管理的bean,它可以通过@Inject
注释注入代码中的任何位置,并且EL解析器也可以通过它的名称#{named-bean-name}
来解析。
要成为支持CDI的bean,一个类必须具有默认构造函数,CDI隐式使用该构造函数来创建类的实例。在某些情况下(例如,如果类没有默认构造函数,或者由于构造函数的可见性受限,或者您需要预初始化bean的实例),创建bean实例的唯一方法是生产方法或字段,它们是曾经是一个bean实例创建源。
@Produces
- 带注释的方法或字段旨在充当注入对象的来源。因此,要创建一个bean的实例,如:
public class SeatType {
public SeatType(Object obj) {}
}
我们需要提供一种生产方法:
public class SeatTypeFactory {
@Produces
public SeatType createSeatType() {
return new SeatType(new Object());
}
}
或生产领域:
public class SeatTypeFactory {
@Produces
private SeatType seatType = new SeatType(new Object());
}
到目前为止,您可以通过注入@Inject
注释在代码中使用它,但尚未在EL中使用。要在EL中解决,您需要在生产字段或生产方法上指定@Named
注释:
@Produces
@Named
private SeatType newSeatType = new SeatType(new Object());
@Produces
@Named("newSeatType")
public SeatType createSeatType() {
return new SeatType(new Object());
}
在您的情况下,您可以通过使用@Named
类的SeatType
进行注释来实现几乎相同(不同之处在于,通过@Produces
创建的bean实例不会被管理本身并不能包含其他注入点):
@Entity
@Table(name = "seat_type")
@Named("newSeatType")
@RequestScoped
public class SeatType implements Serializable {
...
}
答案 1 :(得分:1)
在这个例子中,作者可能过度使用了CDI。您可以像往常一样简单地声明和创建SeatType bean:
private SeatType newSeatType = new SeatType();
并通过页面中的backging bean访问此bean:
<h:inputText id="desc" value="#{theatreSetupService.newSeatType.description}"
您必须为newSeatType属性创建getter和setter。
<强>编辑:强>
另一方面,@ Produces注释仅表示您将能够从应用程序的任何其他CDI bean注入此bean,并且将通过TheatreSetupService CDI bean的newSeatType属性检索注入的bean。但是如果你想通过EL从JSF页面的任何一点注入它,你需要一个qualyfier来消除注入点的歧义。
如果你需要从应用程序中的其他几个bean中注入这个具体的bean,那就不会过度使用了。 在这种情况下,您必须创建一个限定符来区分您的具体bean和全新的bean 。例如:
限定符:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface TheSpecialSeatType{}
制片人:
@Produces
@Named
@TheSpecialSeatType
private SeatType newSeatType;
使用您的混凝土座椅类型的助手类:
public class HelperBean{
// this bean will be the one created inside the backing bean
@Inject
@TheSpecialSeatType
private SeatType theSeatType;
...
}
<强>增加:强>
如果您想直接从您的页面访问该属性(如示例中所示),那么是的,您将需要CDI文档中所述的@Named和@Produces注释。 @Produces通过@Inject注释将生成的bean公开给其他bean,并通过EL公开给JSF页面。
然后,如果你只想在其他bean中注入,只使用@Produces。如果要在JSF页面内部注入,请使用@Produces和@Named。