如何在ManagedBean中注入CDI Bean?

6

我想在ManagedBean中使用@Inject或@Produce注解将CDI Bean注入。我使用的CDI Bean是:

@Named
@Startup
@ApplicationScoped
public class BaseBean {

private List<String> custs;

public List<String> getCusts() {
    return custs;
}

public void setCusts(List<String> emps) {
    this.custs = emps;
}

public BaseBean(){

}

@PostConstruct
void init() {
    custs = new ArrayList<String>();
    custs.add("Cust1");
    custs.add("Cust3");
    custs.add("Cust2");
    custs.add("Cust4");
}

}

我想注入 CDI Bean 的 ManagedBean 如下:

@SessionScoped
@ManagedBean
public class Hello implements Serializable {

@Inject
private BaseBean dBean;

private static final long serialVersionUID = 1L;
private List<String> customers;
private List<String> customersSelect;

public Hello() {
}

@PostConstruct
void init() {
//  dBean = new BaseBean();
    customers = dBean.getCusts();
}

public List<String> getCustomers() {
    return customers;
}

public List<String> getCustomersSelect() {
    return customersSelect;
}

public void setCustomersSelect(List<String> customersSelect) {
    this.customersSelect = customersSelect;
}
}

然而,在init函数中,它抛出了空指针异常。如果我使用注释@Produces而不是@Inject,则结果相同:NullPointerException。CDI Bean有什么问题(注释不正确)?我是否以错误的方式尝试注入它?我的代码是否缺少某些内容?如何使其工作?以下是JSF代码:

<h:form id ="f">
    <h:selectManyCheckbox layout="pageDirection" border="1"  value="#{hello.customersSelect}">
        <f:selectItems value="#{hello.customers}"></f:selectItems>
    </h:selectManyCheckbox><br />
    <h:commandButton action="response.xhtml" value="Click me" />
</h:form>

PS:如果我使用无状态Bean作为BaseBean,并用注释@EJB将其注入,它可以顺利运行。

更新:我已经尝试在Hello类上使用@SessionScopedjavax.enterprise.context.SessionScoped)和@Named注释。虽然我没有收到NullPointerException,但是h:selectManyCheckbox为空。此外,当我在META-INF文件夹下添加beans.xml文件时,我遇到了StartException,尽管该文件应该存在。我认为我的应用缺少适当的配置来实现依赖注入。可能需要额外的配置是什么?

更新2:当我在WEB-INF文件夹中添加beans.xml文件时,出现此错误。 beans.xml文件为空,只包含以下行:

<?xml version="1.0" encoding="UTF-8"?> 

错误信息如下:
Services which failed to start:      service jboss.deployment.unit."JSF1.war".PARSE: org.jboss.msc.service.StartException in service jboss.deployment.unit."JSF1.war".PARSE: Failed to process phase PARSE of deployment "JSF1.war"

12:51:11,482 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 1) {"JBAS014653: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"JBAS014671: Failed services" => {"jboss.deployment.unit.\"JSF1.war\".PARSE" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"JSF1.war\".PARSE: Failed to process phase PARSE of deployment \"JSF1.war\""}}}}
3个回答

9
如果您在CDI环境中工作,请不要使用@ManagedBean。取而代之的是,全程使用CDI。如果您使用@Named来命名CDI bean,那么@patlov的建议将起作用。请参见answer以及其他强烈反对您尝试做的事情的答案。
只需从javax.faces.bean.SessionScoped切换到javax.enterprise.context.SessionScoped,一切都会奇迹般地运行。但是您可能会遇到缺少CDI中的@ViewScoped的情况,在这种情况下,请使用像JBoss Seam或Apache Deltaspike这样为您实现它的框架。作为额外的好处,它们还将自动将所有JSF范围替换为CDI范围,如果您已经有JSF代码编写过的话。
更新: 这应该是beans.xml的内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

@arjacsoh,抱歉,我想我应该提到您应该将@Named添加到任何您想从EL(表达式语言)访问的CDI bean中,即您的页面。因此,请删除@ManagedBean并将Hello替换为@Named。至于异常,请发布堆栈跟踪,否则无法知道问题出在哪里。 - rdcrng
这就是我所做的。我用@Named替换了@ManagedBean,并像您所说的那样添加了import语句javax.enterprise.context.SessionScoped。正如我在更新中所解释的那样,数据没有呈现到JSF页面上。 - arjacsoh
你在更新中还说你遇到了一个启动异常 - 你能贴出那个异常的堆栈跟踪吗? - rdcrng
好的,在调整了beans.xml文件的内容之后,这次它可以工作了。我被书中的内容所误导,认为即使是一个空的beans.xml文件也足以完成工作。 - arjacsoh
是的,这很误导人,因为你仍然需要根元素。 - rdcrng

3

请确保通过在应用程序中放置WEB-INF/beans.xml文件来启用CDI。


当我将它添加到WEB-INF下时,服务器启动时会抛出一个错误:org.jboss.msc.service.StartException。当我将它添加到META-INF下时,服务器可以启动,但问题并没有解决。仍然存在NullPointerException。 - arjacsoh
1
StartException 是正确的方向。很可能现在启用了 CDI,您需要解决一些与 CDI 相关的问题,然后才能使 CDI 正常工作。 - David Blevins
我不知道怎么错过了这个。而且堆栈跟踪也没有给出任何提示。 - Abhishek Tyagi

2
如果您正在使用@ManagedBean,请使用@ManagedProperty来注入属性:
@ManagedProperty(value = "#{baseBean}")
private BaseBean dBean;

// getter and setter

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