JSF 2:能否继承@ManagedBean?

8

我有一个使用@ManagedBean注解并定义如下的Bean


@ManagedBean
@SessionScoped
public class Bean implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

}</code>
</pre>

<p>现在,我有另一个定义如下的<code>Bean</code>:</p>

<pre><code>
public class FooBean extends Bean {
    // properties, methods here ...
}

当我在JSF页面中尝试引用FooBean时,出现以下错误:
目标不可达,标识符“fooBean”解析为null

为什么JSF无法将FooBean视为托管bean?


请参见:https://dev59.com/_VnUa4cB1Zd3GeqPXyQi - Stephan
2个回答

9
亚历克斯想表达的意思是你混淆了类和实例。这是一个经典的面向对象编程错误(OOP mistake)。
@ManagedBean注释并不直接作用于类上,而是作用于这些类的实例上,定义了一个被管理的实例。
如果你的bean像这样定义:
@ManagedBean
@SessionScoped
public class MyBean implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
}

如果您拥有一个会话范围的实例,称为myBean(或任何您想要命名的名称),那么这意味着什么。
因此,默认情况下,所有继承自MyBean类的类都不受管理。此外,JSF如何识别您何时使用子类?如果是这样,您给这些实例取什么名称?(因为您必须给它们一些名称,否则JSF将如何管理它们?)
因此,假设您还有另一个类:
Class MyOtherClass {
    private MyBean myBeanObject; // myBeanObject isn't managed. 
}

当你使用@PostConstruct和其他注解时会发生什么?什么都不会发生。如果你创建了MyBean的实例,那么管理它的是你而不是JavaServerFaces。因此,它并不是真正的托管bean,只是一个普通对象而已。

然而,当你执行以下操作时情况就完全不同了:

@ManagedBean
@SessionScoped
Class MyOtherClassBean {
    @ManagedProperty("#{myBean}")
    private MyBean myBeanObject;

    public void setMyBeanObject(...) { ... }
    public MyBeanClass getMyBeanObject() { ... }
}

再次强调,被管理的不是类,而是类的实例。拥有一个托管的Bean意味着你只有一个该Bean的实例(每个作用域)。


1
感谢您清晰的解释。但是,为什么http://docs.oracle.com/javaee/6/api/javax/faces/bean/ManagedBean.html有@Inherited注释? - Stephan
1
@Stephan 很好的问题。也许这是在实现ManagedBean行为时被放弃的想法。 - The Student

5

您是否需要将BaseBean作为托管bean?由于您将其命名为BaseBean,我假设此bean在所有其他托管bean之间具有共性。如果是这样,那么它不应包含@ManagedBean注释。请这样做:

public abstract BaseBean{
    //...
}

然后在您的托管bean中

@ManagedBean
@RequestScoped
public class FooBean extends BaseBean{
    //...
}

通过这样做,我将不得不在所有的bean上放置@ManagedBean ... 这正是我想避免的! - Stephan
2
@Stephan:为什么你避免在所有托管Bean上放置注释?我不知道您在BaseBean中放置了什么,但从您命名的方式来看,它应该是所有托管Bean之间的共性集,因此您不应将其注释为@ManagedBean,因为它实际上并不是您Model的控制器/网关。您的BaseBean被设置为SessionScoped,因此每个继承自BaseBean的Bean都将是SessionScoped,无论您是否希望如此。您不想在会话中保留太多内容。如果您想创建一个具有RequestScoped并继承自BaseBean的托管Bean,该怎么办呢? - Thang Pham
更明确地说:是否可以继承@ManagedBean? - Stephan

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