@Produces 覆盖成员变量
@Produces over member variable
我试图理解本书 Java EE7 Development with Wildfly 中的一个 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 的影响。创建显然是由 class TheatreSetupService 管理的。对我来说,它看起来就像是成员可用于 jsf 的导出,但 @Named 注释不足以让这个示例工作。谁能解释一下这个小例子中发生了什么?据我所知,这并不经常使用 - 是真的吗?
感谢您的任何提示!
多米尼克
这比 JSF 更特定于 CDI。
@Named
注释是在 CDI 中引入的,旨在成为相同类型的不同 bean 注入的按名称区分的限定符。它还旨在替换以前用 @ManagedBean
注释的 JSF 管理的 bean(如果 运行 在标准 servlet 容器上,如 Tomcat 没有安装 CDI,@ManagedBean
仍然是唯一的解决方案)。因此,一个用 @Named
注释注释的 bean 是一个 CDI 管理的 bean,它可以通过 @Inject
注释注入代码中的任何地方,并且也由 EL 解析器通过其名称解析,如 #{named-bean-name}
。
要成为支持 CDI 的 bean,class 必须具有默认构造函数,CDI 隐式使用它来创建 class 的实例。在某些情况下(例如,如果 class 没有默认构造函数,或者由于构造函数的可见性受限,或者如果您需要预初始化 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());
}
在你的情况下,你可以获得几乎相同的效果,只需用 SeatType
class 的 @Named
进行注释(不同之处在于 beans 实例,通过 @Produces
, 自身不管理,不能包含其他注入点):
@Entity
@Table(name = "seat_type")
@Named("newSeatType")
@RequestScoped
public class SeatType implements Serializable {
...
}
在这个例子中,作者可能过度使用了 CDI。您可以像往常一样简单地声明和创建 SeatType bean:
private SeatType newSeatType = new SeatType();
并通过页面中的后台 bean 访问此 bean:
<h:inputText id="desc" value="#{theatreSetupService.newSeatType.description}"
您必须为 newSeatType 属性创建 getter 和 setter。
已编辑:
另一方面,@Produces 注释仅表示您将能够从应用程序的任何其他 CDI bean 中注入此 bean,注入的 bean 将通过 TheatreSetupService CDI bean 的 newSeatType 属性检索。但是如果你想通过 EL 从 JSF 页面之外的任何点注入它,你将需要一个限定符来消除注入点的歧义。
如果您需要从应用程序中的其他几个 bean 注入这个具体 bean,则不会过度使用。 在这种情况下,您必须创建一个限定符来区分您的具体 bean 和全新的 bean。例如:
预选赛:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface TheSpecialSeatType{}
制片人:
@Produces
@Named
@TheSpecialSeatType
private SeatType newSeatType;
帮手 class 使用您的混凝土座椅类型:
public class HelperBean{
// this bean will be the one created inside the backing bean
@Inject
@TheSpecialSeatType
private SeatType theSeatType;
...
}
已添加:
如果您想直接从您的页面访问该属性,就像在示例中那样,那么是的,您将需要 @Named 和 @Produces 注释,如 CDI 文档中所述。 @Produces 通过@Inject 注释将生成的bean 公开给其他bean,并通过EL 公开给JSF 页面。
然后,如果您只想注入到其他 bean 中,请仅使用 @Produces。如果您想在 JSF 页面内注入,请使用 @Produces 和 @Named。
我试图理解本书 Java EE7 Development with Wildfly 中的一个 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 的影响。创建显然是由 class TheatreSetupService 管理的。对我来说,它看起来就像是成员可用于 jsf 的导出,但 @Named 注释不足以让这个示例工作。谁能解释一下这个小例子中发生了什么?据我所知,这并不经常使用 - 是真的吗?
感谢您的任何提示!
多米尼克
这比 JSF 更特定于 CDI。
@Named
注释是在 CDI 中引入的,旨在成为相同类型的不同 bean 注入的按名称区分的限定符。它还旨在替换以前用 @ManagedBean
注释的 JSF 管理的 bean(如果 运行 在标准 servlet 容器上,如 Tomcat 没有安装 CDI,@ManagedBean
仍然是唯一的解决方案)。因此,一个用 @Named
注释注释的 bean 是一个 CDI 管理的 bean,它可以通过 @Inject
注释注入代码中的任何地方,并且也由 EL 解析器通过其名称解析,如 #{named-bean-name}
。
要成为支持 CDI 的 bean,class 必须具有默认构造函数,CDI 隐式使用它来创建 class 的实例。在某些情况下(例如,如果 class 没有默认构造函数,或者由于构造函数的可见性受限,或者如果您需要预初始化 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());
}
在你的情况下,你可以获得几乎相同的效果,只需用 SeatType
class 的 @Named
进行注释(不同之处在于 beans 实例,通过 @Produces
, 自身不管理,不能包含其他注入点):
@Entity
@Table(name = "seat_type")
@Named("newSeatType")
@RequestScoped
public class SeatType implements Serializable {
...
}
在这个例子中,作者可能过度使用了 CDI。您可以像往常一样简单地声明和创建 SeatType bean:
private SeatType newSeatType = new SeatType();
并通过页面中的后台 bean 访问此 bean:
<h:inputText id="desc" value="#{theatreSetupService.newSeatType.description}"
您必须为 newSeatType 属性创建 getter 和 setter。
已编辑:
另一方面,@Produces 注释仅表示您将能够从应用程序的任何其他 CDI bean 中注入此 bean,注入的 bean 将通过 TheatreSetupService CDI bean 的 newSeatType 属性检索。但是如果你想通过 EL 从 JSF 页面之外的任何点注入它,你将需要一个限定符来消除注入点的歧义。
如果您需要从应用程序中的其他几个 bean 注入这个具体 bean,则不会过度使用。 在这种情况下,您必须创建一个限定符来区分您的具体 bean 和全新的 bean。例如:
预选赛:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface TheSpecialSeatType{}
制片人:
@Produces
@Named
@TheSpecialSeatType
private SeatType newSeatType;
帮手 class 使用您的混凝土座椅类型:
public class HelperBean{
// this bean will be the one created inside the backing bean
@Inject
@TheSpecialSeatType
private SeatType theSeatType;
...
}
已添加:
如果您想直接从您的页面访问该属性,就像在示例中那样,那么是的,您将需要 @Named 和 @Produces 注释,如 CDI 文档中所述。 @Produces 通过@Inject 注释将生成的bean 公开给其他bean,并通过EL 公开给JSF 页面。
然后,如果您只想注入到其他 bean 中,请仅使用 @Produces。如果您想在 JSF 页面内注入,请使用 @Produces 和 @Named。