一尘不染

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

spring

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

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

如果要在此managedBean中注入某些组件(来自Spring),则有两种可能的方法:

  1. 在ManagedBean中选择属性(例如“ BasicDAO dao”),然后@ManagedProperty(#{"basicDAO"})在该属性上方进行声明。这样做,我是将”basicDAO”Spring中的bean注入ManagedBean中。

  2. 在ManagedBean类中声明为@Controller,然后将同时具有@ManagedBean@Controller批注。在财产上,"BasicDAO dao"我必须@Autowired从Spring 使用。

我的理解正确吗?


阅读 645

收藏
2020-04-11

共2个答案

一尘不染

通过简单地从中扩展JSF bean,还有另一种在JSF管理bean中使用Spring管理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.
}
2020-04-11
一尘不染

@ManagedBean vs @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,@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

特定@ManagedProperty于JSF的功能仅在JSF管理的Bean中有效,即在使用时@ManagedBean。特定@Autowired于Spring的功能仅在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.
}

请注意,按照javadoc进行SpringBeanFacesELResolver注册后,faces-config.xml

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

因此,你可以通过引用EL中的Spring托管bean #{springBeanName},然后也可以引用它们@ManagedProperty,因为它基本上设置了给定EL表达式的求值结果。相反,@Autowired完全不支持通过注入JSF管理的bean 。但是@Autowired,当你从扩展Bean时,可以在JSF托管Bean中使用SpringBeanAutowiringSupport。在构造函数调用期间,这@Autowired将在Spring可自动上下文中自动注册JSF托管bean实例,这意味着所有功能都将在@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 autowirable上下文中手动注册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是通过新@FlowScoped注释在JSF 2.2中接管的。因此,如果你碰巧已经在JSF 2.2上,那么如果你只想要流范围,就不必使用Spring WebFlow。

CDI - trying to unify it all

从Java EE 6开始,CDI被提供为Spring DI的标准替代品。它分别具有@Named和的@Inject注释,以及它自己的范围集。我不是很清楚如何与Spring交互,因为我不使用Spring,但@Inject内部的工作@ManagedBean,并且@ManagedProperty内部@ManagedBean可以引用@Named豆。另一方面,@ManagedProperty@Namedbean 内部不起作用。

CDI的目的是将所有不同的bean管理框架统一为一个规范/接口。Spring可能是完整的CDI实现,但他们选择仅部分实现它(仅javax.inject.*支持JSR-330 ,但javax.enterprise.context.*不支持JSR-299 )。另请参阅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.
    }
}
2020-04-11