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

我知道托pipebean像控制器一样工作,因为唯一的任务是将视图层与模型“链接”。

要使用bean作为托pipebean,我必须声明@ManagedBean注释,这样才能直接与bean通信。

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

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

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

我的理解是正确的吗?

@ManagedBean@Controller

首先,你应该select一个框架来pipe理你的豆子。 您应该selectJSF或Spring(或CDI)来pipe理您的bean。 虽然以下的工作,这是根本的错误:

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

你最终得到两个完全独立的同一托pipebean类的实例,一个由JSFpipe理,另一个由Springpipe理。 当你将其引用为#{someBean}时,并不直接清楚在EL中实际使用哪一个。 如果你在faces-config.xml注册了SpringBeanFacesELResolver ,那么它将是Springpipe理的,而不是JSFpipe理的。 如果你没有这个,那么JSFpipe理的就是这个。

此外,当您声明JSF托pipebean特定范围时,例如@SessionScoped @ViewScoped@SessionScoped @ViewScoped@SessionScoped或来自javax.faces.*包的@ApplicationScoped ,它将仅被@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时,它将返回Springpipe理的应用程序范围的bean,而不是JSFpipe理的视图范围的bean。


@ManagedProperty@Autowired

特定于JSF的@ManagedProperty只能在JSFpipe理的bean中使用,即当你使用@ManagedBean 。 特定于Spring的@Autowired只能在Springpipe理的bean中使用,即当你使用@Controller 。 下面的方法是更less或更相当的,不能混合:

 @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在faces-config.xml注册SpringBeanFacesELResolver时,

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

因此你可以通过#{springBeanName}引用EL中的Spring托pipebean,然后你可以在@ManagedProperty引用它们,因为它基本上设置了给定ELexpression式的求值结果。 @Autowired ,通过@Autowired注入一个JSF托pipebean,是不支持的。 但是,如果您在下面的Spring自动上下文中手动注册JSF托pipebean实例,则可以在JSF托pipebean中使用@Autowired 。 另请参见如何将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 vs @Scope

Spring的@Scope对JSF范围提供了有限的支持。 JSF的@ViewScoped没有等价物。 基本上,您可以自己创build自己的作用域,或者坚持在Spring自动上下文环境中手动注册JSF托pipebean实例,如上所示。

另一方面,Spring WebFlow通过新的@FlowScoped注解被JSF 2.2 @FlowScoped 。 所以,如果你已经在JSF 2.2上了,那么如果你仅仅需要stream程范围,那么你不一定需要使用Spring WebFlow。


CDI – 试图统一一切

从Java EE 6开始,CDI是Spring DI的标准替代品。 它分别具有@Named@Inject注释,还有它自己的一组作用域。 我不确定它如何与Spring交互,因为我不使用Spring,但@Inject@ManagedBean ,@ @ManagedProperty@ManagedBean可以引用@Named bean。 另一方面,@ @ManagedProperty@Named bean中不起作用。

CDI的目的是将所有不同的beanpipe理框架统一为一个规范/接口。 Spring可能是一个完整的CDI实现,但他们select只部分实现它(只支持JSR-330 javax.inject.* ,而不支持JSR-299 javax.enterprise.context.* )。 请参阅Will Spring是否支持CDI? 和本教程 。

JSF将转移到CDI进行beanpipe理,并在未来的版本中弃用@ManagedBean和朋友。

也可以看看:

  • 什么时候使用Spring或者EJB3或者全部使用它们是必要的还是方便的?
  • JSF服务层
  • 支持豆(@ManagedBean)或CDI豆(@Named)?
  • 使用JSF作为Spring MVC的视图技术
  • 如何在Tomcat上安装和使用CDI?

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

由我编辑。 我build议要么完全通过注释@Managed和@Component或通过XML来实现它们。