JSF 托管 bean EJB 注入

Posted

技术标签:

【中文标题】JSF 托管 bean EJB 注入【英文标题】:JSF managed-bean EJB injection 【发布时间】:2012-01-27 10:01:32 【问题描述】:

我在企业应用程序模块中有一个 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 Web 应用程序中使用 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。我做错了什么?

但是如果我像这样将 PersonManager 注入到 JSF 托管 bean 中:

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

它工作正常。我需要第一个场景,请帮帮我:-D

【问题讨论】:

为什么不用@EJB注解代替在faces-config.xml中手动声明呢?这就像在没有发明注释时试图回到过去:P 你是对的 :-D 这只是理论上的,我想知道答案。 @Forty 那么为什么它不起作用呢?我不清楚答案。 【参考方案1】:

您正在混合 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);
    

    // ...

【讨论】:

谢谢,PersonManager 是一个业务 EJB,因此不包含 @ManagedBean 注释。它是由 JSF 引擎创建的,只是在 faces-config 场景下没有将 person EJB 注入其中。 我知道 EJB 是什么以及应该如何使用它们。你?究竟是哪一部分现在还不清楚? 请注意,我的答案示例中缺少@Stateful。它不是这样的 EJB。您试图将 EJB 滥用为 JSF 托管 bean。这个不对。您基本上应该有 1 个 Xhtml 文件作为视图,1 个 JSF 托管 bean 作为控制器,1 个实体作为模型和 1 个 EJB 作为服务。在您的问题中,PersonManager 应该是 JSF 托管 bean,而不是 EJB。 PersonLocal 似乎是一个实体,而不是 EJB。所以我怀疑它是否真的需要成为 EJB。 EJB 旨在提供create()save() 等服务。 另请参阅更新的答案以获取启动示例。请注意,您根本不需要配置 xml 文件。 我在看答案的同时也很佩服作者,但是当我读到最后,看到底部有你的名字“BalacC”,我的兴奋感降低了。难怪只有你能写出这么好的答案。祝你好运

以上是关于JSF 托管 bean EJB 注入的主要内容,如果未能解决你的问题,请参考以下文章

将 JSF2 托管 pojo bean 传递到 EJB 或将所需内容放入传输对象

Spring JSF 集成:如何在 JSF 托管 bean 中注入 Spring 组件/服务?

使用@EJB 时,每个托管bean 是不是都有自己的@EJB 实例?

Managed Bean中的EJB3.0 @EJB注释JSF2 Websphere 7是不可能的?

CDI 托管 bean 和 JSF 托管 bean 可以相互通信吗?

使用 CDI(上下文和依赖注入)支持 bean 而不是托管 Bean