Spring JSF集成:如何在JSF托pipebean中注入Spring组件/服务?
我知道托pipebean像控制器一样工作,因为唯一的任务是将视图层与模型“链接”。
要使用bean作为托pipebean,我必须声明@ManagedBean
注释,这样才能直接与bean通信。
如果我想在这个managedBean中注入一些组件(从Spring),我有两种可能的方式:
-
selectManagedBean中的属性(如“BasicDAO dao”),并在属性上方声明
@ManagedProperty(#{"basicDAO"})
。 这样做,我在"basicDAO"
从Spring注入bean"basicDAO"
。 -
在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来实现它们。