47

我了解托管 bean 的工作方式类似于控制器,因为您唯一的任务是将视图层与模型“链接”。

要将 bean 用作托管 bean,我必须声明@ManagedBean注释,这样做我可以直接与 bean 通信 JSF。

如果我想在这个 managedBean 中注入一些组件(来自 Spring),我有两种可能的方法:

  1. 选择 ManagedBean 中的属性(如“BasicDAO dao”)并@ManagedProperty(#{"basicDAO"})在属性上方声明。这样做,我"basicDAO"在 ManagedBean 中从 Spring 注入 bean。

  2. 在 ManagedBean 类中声明 @Controller,然后我将拥有@ManagedBean@Controller注释,所有这些。在财产方面,"BasicDAO dao"我必须@Autowired从 Spring 开始使用。

我的理解正确吗?

4

4 回答 4

97

@ManagedBean对比@Controller

首先,您应该选择一个框架来管理您的 bean。您应该选择 JSF 或 Spring(或 CDI)来管理您的 bean。尽管以下方法有效,但它从根本上是错误的:

@ManagedBean // JSF-managed.
@Controller // Spring-managed.
public class BadBean {}

您最终会得到同一个托管 bean 类的两个完全独立的实例,一个由 JSF 管理,另一个由 Spring 管理。当您将EL引用为#{someBean}. 如果您在 中SpringBeanFacesELResolver注册faces-config.xml,那么它将是 Spring 管理的,而不是 JSF 管理的。如果您没有,那么它将是 JSF 管理的。

此外,当您声明 JSF 托管 bean 特定范围时,例如@RequestScoped、或from包,它只会被. 它不会被理解,因为它期望有自己的注释。缺席时默认为单例(应用程序范围)。@ViewScoped@SessionScoped@ApplicationScopedjavax.faces.*@ManagedBean@Controller@Scope

@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
@Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}

当您通过 引用上述 bean 时#{someBean},它将返回 Spring 管理的应用程序范围 bean,而不是 JSF 管理的视图范围 bean。


@ManagedProperty对比@Autowired

JSF-specific@ManagedProperty仅适用于 JSF 管理的 bean,即当您使用@ManagedBean. Spring-specific@Autowired仅适用于 Spring 管理的 bean,即当您使用@Controller. 以下方法或多或少等效,不能混合使用:

@ManagedBean // JSF-managed.
@RequestScoped // JSF-managed scope.
public class GoodBean {

    @ManagedProperty("#{springBeanName}")
    private SpringBeanClass springBeanName; // Setter required.
}
@Component // Spring-managed.
@Scope("request") // Spring-managed scope.
public class GoodBean {

    @Autowired
    private SpringBeanClass springBeanName; // No setter required.
}

请注意,当您按照javadocSpringBeanFacesELResolver进行注册时,faces-config.xml

<application>
    ...
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

因此您可以通过 EL 在 EL 中引用 Spring 托管 bean #{springBeanName},然后您也可以在其中引用它们@ManagedProperty,因为它基本上设置了给定 EL 表达式的评估结果。反过来,通过 注入 JSF 托管的 bean @Autowired,则完全不受支持。但是@Autowired,当您从SpringBeanAutowiringSupport. 这将在构造函数调用期间自动在 Spring 自动装配上下文中注册 JSF 托管 bean 实例,这意味着一切都@Autowired将在以后可用@PostConstruct

@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport implements Serializable {

    @Autowired
    private SpringBeanClass springBeanName; // No setter required.

    @PostConstruct
    private void init() {
        // springBeanName is now available.
    }
}

或者当您的架构不允许从不同的基类扩展 bean 时,您始终可以在 Spring 自动装配上下文中手动注册 JSF 托管 bean 实例,如下所示。另请参阅如何很好地集成 JSF 2 和 Spring 3(或 Spring 4)以获得技巧。

@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {

    @Autowired
    private SpringBeanClass springBeanName; // No setter required.

    @PostConstruct
    private void init() {
        FacesContextUtils
            .getRequiredWebApplicationContext(FacesContext.getCurrentInstance())
            .getAutowireCapableBeanFactory().autowireBean(this);

        // springBeanName is now available.
    }
}

@XxxScoped对比@Scope

Spring@Scope对 JSF 作用域的支持有限。JSF 的@ViewScoped. 您基本上要么自行开发自己的范围,要么坚持在 Spring 自动装配上下文中手动注册 JSF 托管 bean 实例,如上所示。

而且,从另一方面来说,Spring WebFlow 在 JSF 2.2 中通过新的@FlowScoped注解被接管了。因此,如果您碰巧已经使用 JSF 2.2,那么如果您只想要流范围,则不一定需要使用 Spring WebFlow。


CDI - 试图统一一切

从 Java EE 6 开始,CDI 作为 Spring DI 的标准替代品提供。它分别具有对此@Named@Inject注释以及它自己的一组范围。我不确定它如何与 Spring 交互,因为我不使用 Spring,但@Inject在 a 中工作@ManagedBean,并且@ManagedProperty在 a@ManagedBean中可以引用@Namedbean。另一方面,在bean@ManagedProperty中不起作用。@Named

CDI 的目的是将所有不同的 bean 管理框架统一到一个规范/接口中。Spring 可能是一个完整的 CDI 实现,但他们选择仅部分实现它(仅支持 JSR-330 javax.inject.*,但不支持 JSR-299 javax.enterprise.context.*)。另请参阅Spring 是否支持 CDI?本教程

JSF 将移至 CDI 进行 bean 管理,@ManagedBean并在未来的版本中弃用。

@Named // CDI-managed.
@ViewScoped // CDI-managed scope.
public class BetterBean implements Serializable {

    @Inject
    private SpringBeanClass springBeanName; // No setter required.

    @PostConstruct
    private void init() {
        // springBeanName is now available.
    }
}

也可以看看:

于 2013-08-22T18:34:17.057 回答
14

还有另一种在 JSF 管理的 bean 中使用 Spring 管理的 bean 的方法,方法是简单地扩展 JSF bean SpringBeanAutowiringSupport,Spring 将处理依赖注入。

@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport {

    @Autowired
    private SpringBeanClass springBeanName; // No setter required.

    // springBeanName is now available.
}
于 2017-11-30T22:15:50.233 回答
1

最简单的方法是通过 XML。我使用@Component了已经制作的 jsf 托管 bean,但@Autowired没有工作,因为托管 bean 已经存在于 faces-config.xml 中。如果必须在 xml 文件中保留该托管 bean 定义及其托管属性,则建议将 spring bean 添加为托管 bean 标记内的另一个托管属性。这里的 spring bean 是在 spring-config.xml 中定义的(可以在某个地方交替自动装配)。请参考 https://stackoverflow.com/a/19904591/5620851

由我编辑。我建议要么通过注释 @Managed 和 @Component 完全实现它,要么通过 xml 来实现它。

于 2016-10-14T09:04:15.400 回答
0

@Autowired您可以在不利用getBean当前 WebApplication 上下文的情况下自动装配各个 bean 。

有关更多详细信息,请参阅@BalusC 的答案。这只是对他的示例的轻微修改:

@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {

    // @Autowired // No Autowired required
    private SpringBeanClass springBeanName; // No setter required.

    @PostConstruct
    private void init() {
        WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
        this.springBeanName = ctx.getBean(SpringBeanClass.class);
        // springBeanName is now available.
    }
}
于 2021-10-14T11:52:34.083 回答