JSF 管理的 bean 中 EJB 注入

20

我有一个位于企业应用程序模块中的EJB(PersonManager),它注入另一个EJB(Person):

@Stateful
public class PersonManager implements PersonManagerLocal {
    @EJB
    private PersonLocal person;

    @Override
    public void setPersonName(String name) {
        person.setName(name);
    }

    @Override
    public String getPersonName() {
        return person.getName();
    }
}

我想在一个JSF网站应用程序中使用PersonManager EJB。我在faces-config.xml文件中定义了它:

<managed-bean>
    <managed-bean-name>personManager</managed-bean-name>
    <managed-bean-class>ejb.PersonManager</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

问题在于,PersonLocal EJB的注入没有发生。person属性始终为NULL。我错在了哪里?

但如果我像这样在JSF管理的bean中注入PersonManager:

@ManagedBean
@RequestScoped
public class Index {
    @EJB
    private PersonManagerLocal personManager;
    ....

它有效。我需要第一种情况,请帮帮我 :-D


为什么不使用@EJB注释,而是手动在faces-config.xml中声明?这就像试图回到注释未被发明的过去一样 :P - Mr.J4mes
你是对的 :-D 这只是理论上的,我想知道答案。 - Forty
@Forty,为什么它不起作用?对我来说答案并不清楚。 - Koray Tugay
1个回答

42
你混淆了EJB和JSF管理的bean的职责。 faces-config.xml 只注册JSF工件,如托管bean而不是EJB。你在faces-config.xml中的注册方式是不正确的。
<managed-bean>
    <managed-bean-name>personManager</managed-bean-name>
    <managed-bean-class>ejb.PersonManager</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

基本上完全与...相同

@ManagedBean
@SessionScoped
public class PersonManager {
    // ...
}
换句话说,你正在将该类注册为JSF托管bean,可以在视图中通过#{personManager}使用。这不代表由EJB容器管理的实例。您不能且不应该使用faces-config.xml来注册EJB。您需要使用javax.ejb包中的注释,例如@Stateless@Stateful。这就是您注册EJB所需的全部内容。
事实上,在faces-config.xml中注册JSF托管bean是旧的JSF 1.x方法,在JSF 2.x中已被新的@ManagedBean注解替换。
更新,正确的方法是:
视图(Facelets文件):
<h:form>
    <h:inputText value="#{personManager.person.name}" />
    ...
    <h:commandButton value="Save" action="#{personManager.save}" />
    <h:messages />
</h:form>

控制器(JSF 管理的 Bean):

@ManagedBean
@ViewScoped
public class PersonManager implements Serializable {

    private Person person;

    @EJB
    private PersonService personService;

    @PostConstruct
    public void init() {
        person = new Person();
    }

    public void save() {
        personService.create(person);
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage("Person successfully created, new ID is " + person.getId()));
    }

    // ...
}

模型(JPA实体):

@Entity
public class Person implements Serializable {

    @Id
    private Long id;

    private String name;

    // ...
}

服务(无状态 EJB):

@Stateless
public class PersonService {

    @PersistenceContext
    private EntityManager em;

    public void create(Person person) {
        em.persist(person);
    }

    // ...
}

我知道什么是EJB以及它们应该如何使用。你呢?现在还有哪一部分不清楚吗? - BalusC
4
请注意,在我的答案示例中缺少@Stateful。这样就不是EJB了。您试图将EJB误用为JSF托管bean,这是不正确的。基本上,您应该有一个XHTML文件作为视图,1个JSF托管bean作为控制器,1个实体作为模型和1个EJB作为服务。在您的问题中,PersonManager应该是JSF托管bean,而不是EJB。PersonLocal看起来更像是一个实体而不是EJB,因此我怀疑它是否真的需要成为EJB。EJB旨在提供诸如create()save()等服务。 - BalusC
请注意,您根本不需要配置XML文件。参见启动示例的更新答案。 - BalusC
@BalusC,如果您的示例中的PersonManager恰好是@SessionScoped而不是@ViewScoped,那么PersonService是否应该通过InitialContext查找而不是被注入? - Patrick Garner
2
我正在阅读这篇答案,同时也在欣赏作者的才华。但当我看到底部的名字“BalacC”时,我的兴奋感降低了。难怪只有你能写出这样好的答案。祝你好运! - ehsun7b
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接