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

时间:2013-08-22 18:18:12

标签: spring jsf dependency-injection integration managed-bean

我知道托管bean的工作方式类似于控制器,因为您的唯一任务是将View Layer与Model“链接”。

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

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

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

  2. 在ManagedBean Class中声明了@Controller,然后我将同时拥有@ManagedBean@Controller注释。在属性"BasicDAO dao"中,我必须使用Spring的@Autowired

  3. 我的理解是否正确?

3 个答案:

答案 0 :(得分:75)

@ManagedBean vs @Controller

首先,您应该选择一个框架来管理您的bean。您应该选择JSF或Spring(或CDI)来管理您的bean。虽然以下工作,但从根本上说是错误的:

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

你最终得到了同一个托管bean类的两个完全独立的实例,一个由JSF管理,另一个由Spring管理。当你将它作为#{someBean}引用时,并不清楚哪一个实际在EL中使用。如果您在faces-config.xml中注册SpringBeanFacesELResolver,则它将由Spring管理,而不是由JSF管理的。{1}}。如果你没有,那就是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 {}

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


@ManagedProperty vs @Autowired

特定于JSF的@ManagedProperty仅适用于JSF托管的bean,即当您使用@ManagedBean时。特定于Spring的@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.
}

请注意,根据SpringBeanFacesELResolver faces-config.xml<application> ... <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application> 注册javadoc时,

#{springBeanName}

因此您可以通过@ManagedProperty在EL中引用Spring托管bean,然后您也可以在@Autowired中引用它们,因为它基本上设置了给定EL表达式的评估结果。反过来说,通过@Autowired注入JSF托管bean是不可支持的。但是,当您在Spring自动上传的上下文中手动注册JSF托管bean实例时,可以在JSF托管bean中使用@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. } } 。另请参阅How to integrate JSF 2 and Spring 3 (or Spring 4) nicely了解诀窍。

@XxxScoped

@Scope vs @Scope

Spring的@ViewScoped对JSF范围的支持有限。 JSF的@FlowScoped没有等价物。您基本上要么自己创建自己的作用域,要么坚持在Spring自动化上下文中手动注册JSF托管bean实例,如上所示。

而且,另一方面,Spring WebFlow通过新的@Named注释在JSF 2.2中被接管。因此,如果您刚好使用JSF 2.2,那么如果您只想要流量范围,则不一定需要使用Spring WebFlow。


CDI - 试图统一一切

自Java EE 6起,CDI作为Spring DI的标准替代品提供。它分别有@Inject@Inject注释以及它自己的范围集。我不确定它是如何与Spring交互的,因为我不使用Spring,但@ManagedBean@ManagedProperty内部工作,而@ManagedBean内的@Named可以引用{ {1}} bean。另一方面,@ManagedProperty@Named bean中不起作用。

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

JSF将转向CDI进行bean管理,并在将来的版本中弃用@ManagedBean和朋友。

另见:

答案 1 :(得分:6)

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

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

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

    // springBeanName is now available.
}

答案 2 :(得分:1)

这样做的简单方法是通过XML。我在已经创建的jsf托管bean中使用了.directive('scrollBottom', ['$timeout' , function ($timeout) { return { link: function (scope, element) { $timeout(function () { console.log($(element).scrollTop()) $(element).scrollTop($(element)[0].scrollHeight) }) } } } 但是@Component没有用,因为托管bean已经存在于faces-config.xml中。如果必须将该托管bean定义及其托管属性保留在xml文件中,则建议将spring bean添加为托管bean标记内的另一个托管属性。这里的spring bean是在spring-config.xml中定义的(可以在某处交替自动装配)。请参考 https://stackoverflow.com/a/19904591/5620851

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