EJB方法不是从构造函数调用

时间:2012-09-25 05:30:28

标签: jsf-2 ejb-3.0

我创建了一个ejb

@Stateless
@LocalBean   
public class BasitBean {

    public String helloBasit() {

        return "Basit";

    } //end of helloBasit()

} //end of class BasitBean

我从JSF中调用它,如

<h:body>

    <h:outputLabel value="#{helloBasit.callBasit()}" />

</h:body>

@ManagedBean
@SessionScoped
public class HelloBasit {

    @EJB
    private BasitBean basitBean;

    /** Creates a new instance of HelloBasit */
    public HelloBasit() {         

    }

    public String callBasit() {

        return basitBean.helloBasit();

    } //end of callBasit()

} //end of class HelloBasit

此代码工作正常。但是当我改变像这样的代码时

<h:body>
    <h:outputLabel value="#{helloBasit.label}" />        
</h:body>

@ManagedBean
@SessionScoped
public class HelloBasit {

    @EJB
    private BasitBean basitBean;
    String label;

    /** Creates a new instance of HelloBasit */
    public HelloBasit() {

        System.out.println();
        String label = basitBean.helloBasit();
        System.out.println(label);

    }

    public BasitBean getBasitBean() {
        return basitBean;
    }

    public void setBasitBean(BasitBean basitBean) {
        this.basitBean = basitBean;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

} //end of class HelloBasit

然后我得到了例外

SEVERE: Error Rendering View[/index.xhtml]
com.sun.faces.mgbean.ManagedBeanCreationException: Cant instantiate class: pk.mazars.basitMahmood.HelloBasit.
 at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:193)
 at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:102)
 ......

为什么我得到这个例外?当我的页面遇到#{helloBasit.label}然后我的构造函数调用,实例变量初始化,将bean实例注入basitBean,然后bean方法应该调用时,流程应该是我理解的。但是在这种情况下,我在bean实例中得到null为什么?为什么以前的代码有效,但事实并非如此?如何从构造函数中调用bean?

谢谢。

2 个答案:

答案 0 :(得分:7)

尝试将构造函数的内容移动到post构造函数中......

像这样

@PostConstruct
private void init() {
    System.out.println();
    String label = basitBean.helloBasit();
    System.out.println(label);
}

因为只有在启动托管bean之后才应该注入ejb bean

构造函数之后运行@PostConstruct(之后由JSF创建托管bean本身),然后只将EJB注入bean并且可以访问...

答案 1 :(得分:0)

你的想法是正确的,但我看到一些可以解决的问题。

    如果您的EJB没有直接实现接口,则不需要
  • @LocalBean注释。在这种情况下,无论是否有@LocalBean注释,您都会产生相同的效果。如果你想让它明确,你可以离开。请参阅this

  • 确保从@ManagedBean包中导入@SessionScopedjavax.faces.bean

请看这个工作样本:

<强> EJB

import javax.ejb.Stateless;

@Stateless
public class PersonService { 

    public String getName() {
        return "Cloud Strife";
    }
}

托管Bean

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class PersonBean {

    @EJB
    private PersonService ps;

    private String name;

    @PostConstruct
    public void init() {
        name = ps.getName();
    }

    public String getName() {    
        return name;
    }
}

XHTML页面

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">

    <f:view contentType="text/html">
        <h:head>
            <title>Test</title>
        </h:head>
        <h:body>
            <h1>Welcome, #{personBean.name}</h1>
        </h:body>
    </f:view>

</html>

如果你的值只应加载一次,比如你的bean构造,总是更喜欢带有@PostConstruct注释的方法而不是构造函数。

此外,为了在呈现视图之前调用bean方法,您可以使用f:event标记,例如:

<f:event type="preRenderView" listener="#{personBean.init}" />

我希望它有所帮助!