@Produces over成员变量

时间:2015-10-19 21:56:57

标签: jsf cdi

我试着从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注释不足以使这个例子起作用。谁能解释一下这个小例子会发生什么?据我所知,这种情况并不经常使用 - 这是真的吗?

感谢您的任何提示!

2 个答案:

答案 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。