Spring JSF集成:如何在JSF管理的bean中注入Spring组件/服务? [英] Spring JSF integration: how to inject a Spring component/service in JSF managed bean?
问题描述
要将bean用作托管bean,我必须声明 @ManagedBean
注释,做到这一点我可以与JSF通信豆直接。
如果我想在这个managedBean中注入一些组件(从Spring),我有两种可能的方式:
-
选择ManagedBean中的属性(如BasicDAO dao),并声明属性上方的
@ManagedProperty(#{basicDAO})
。做这个,我从ManagedBean的Spring中注入beanbasicDAO
。 -
在ManagedBean类中声明@Controller,那么我将有
@ManagedBean
和@Controller
注释,全部在一起。而在属性BasicDAO dao
中,我必须使用Spring中的@Autowired
。
我的理解是否正确?
@ManagedBean
vs @Controller
首先,你应该选择一个框架来管理您的bean。您应该选择JSF或Spring(或CDI)来管理您的bean。以下工作原理是错误的:
@ManagedBean // JSF管理。
@Controller // Spring管理。
public class BadBean {}
你最终得到两个完全独立的一个托管bean类的实例,一个由JSF管理,另一个由Spring管理。当您将其引用为#{someBean}
时,不会直接清楚在EL中实际使用哪一个。如果您有 在
,那么它将是Spring管理的,不是JSF管理的一个。如果你没有这个,那么这将是JSF管理的一个。 faces-config.xml
中注册的SpringBeanFacesELResolver
另外,当你声明一个JSF托管bean的具体作用域,如 @RequestScoped
, @ViewScoped
, @SessionScoped
或 @ApplicationScoped
从 javax.faces。*
包,它只会被 @ManagedBean
。它不会被 @Controller
理解,因为它希望自己的 @Scope
注释。缺省时默认为单例(应用范围)。
@ManagedBean // JSF管理。
@ViewScoped // JSF管理范围。
@Controller // Spring管理(没有自己的范围,所以实际上成为一个单例)。
public class BadBean {}
当您通过#{someBean}
,它将返回Spring管理的应用程序作用域bean,而不是JSF管理的视图作用域bean。
@ManagedProperty
vs @Autowired
JSF特定的 @ManagedProperty
仅在JSF管理的bean中工作,即使用 @ManagedBean
。 Spring特定的 @Autowired
仅在Spring管理的bean中工作,即使用 @Controller
时。以下方法较少或更多的等效且不能混合:
@ManagedBean // JSF管理。
@RequestScoped // JSF管理范围。
public class GoodBean {
@ManagedProperty(#{springBeanName})
private SpringBeanClass springBeanName; //需要Setter
}
@Component // Spring管理。
@Scope(request)// Spring管理范围。
public class GoodBean {
@Autowired
private SpringBeanClass springBeanName; //不需要设置器
}
请注意,当您有 SpringBeanFacesELResolver
根据 faces-config.xml 中-api / org / springframework / web / jsf / el / SpringBeanFacesELResolver.htmlrel =nofollow noreferrer> javadoc ,
<应用>
...
< el-resolver> org.springframework.web.jsf.el.SpringBeanFacesELResolver< / el-resolver>
< / application>
因此,您可以通过#{springBeanName}引用EL中的Spring托管bean
,那么您也可以在 @ManagedProperty
中引用它们,因为它基本上设置给定EL表达式的评估结果。另一方面,通过 @Autowired
注入JSF托管的bean是没有任何支持的。当您在Spring自动可读上下文中手动注册JSF托管bean实例时,您可以在JSF托管bean中使用 @Autowired
。另请参见如何集成JSF 2和Spring 3(或Spring 4)很棒的窍门。
@ManagedBean // JSF管理。
@ViewScoped // JSF管理范围。
public class GoodBean实现Serializable {
@Autowired
private SpringBeanClass springBeanName; //不需要设置器
@PostConstruct
private void init(){
FacesContextUtils
.getRequiredWebApplicationContext(FacesContext.getCurrentInstance())
.getAutowireCapableBeanFactory()。autowireBean(this );
// springBeanName现在可用。
}
}
@XxxScoped
vs @Scope
Spring's @Scope
对JSF范围的支持有限。没有等同于JSF的 @ViewScoped
。您基本上可以自己创建自己的范围,或者坚持在Spring autowirable上下文中手动注册JSF托管bean实例。
而从另一方面Spring WebFlow通过新的 @FlowScoped
注释在JSF 2.2中被接管。所以如果你碰巧在JSF 2.2上,那么如果你只想要流程范围,那么你不一定需要使用Spring WebFlow。
CDI - 试图统一它所有
由于Java EE 6,CDI作为Spring DI的标准替代品提供。它分别具有 @Named
和 @Inject
注释以及它自己的一组范围。我不知道如何与Spring进行交互,因为我不使用Spring,但是 @Inject
在$ code> @ManagedBean bean。另一方面, @ManagedProperty
在 @Named
bean中不起作用。
CDI的目的是将所有不同的bean管理框架统一为一个规范/界面。 Spring可能是一个完整的CDI实现,但他们选择仅部分实现它(只支持JSR-330 javax.inject。*
,但JSR-299 javax.enterprise.context。*
not)。另请参见 Will Spring支持CDI?和本教程。
JSF将转向CDI进行bean管理,并在以后的版本中弃用 @ManagedBean
和朋友。
另请参见:
- 什么时候使用Spring或EJB3或它们全部在一起吗?
- JSF服务层
- 支持bean(@ManagedBean)或CDI Bean(@Named)?
- 使用JSF作为Spring MVC的查看技术
- 如何在Tomcat上安装和使用CDI?
I understand that a managed bean works like a controller, because your only task is "link" the View Layer with Model.
To use a bean as a managed bean I must declare @ManagedBean
annotation, doing that I can communicate JSF with bean directly.
If I want to inject some component (from Spring) in this managedBean I have two possibles ways:
Choose the property in ManagedBean (like "BasicDAO dao") and declare
@ManagedProperty(#{"basicDAO"})
above the property. Doing it, i'm injecting the bean"basicDAO"
from Spring in ManagedBean.Declared @Controller in ManagedBean Class, then i'll have
@ManagedBean
and@Controller
annotations, all together. And in property"BasicDAO dao"
i must use@Autowired
from Spring.
Is my understanding correct?
@ManagedBean
vs @Controller
First of all, you should choose one framework to manage your beans. You should choose either JSF or Spring (or CDI) to manage your beans. Whilst the following works, it is fundamentally wrong:
@ManagedBean // JSF-managed.
@Controller // Spring-managed.
public class BadBean {}
You end up with two completely separate instances of the very same managed bean class, one managed by JSF and another one managed by Spring. It's not directly clear which one would actually be used in EL when you reference it as #{someBean}
. If you have the SpringBeanFacesELResolver
registered in faces-config.xml
, then it would be the Spring-managed one, not the JSF-managed one. If you don't have that, then it would be the JSF-managed one.
Also, when you declare a JSF managed bean specific scope, such as @RequestScoped
, @ViewScoped
, @SessionScoped
or @ApplicationScoped
from javax.faces.*
package, it will only be recognized and used by @ManagedBean
. It won't be understood by @Controller
as it expects its own @Scope
annotation. This defaults to singleton (application scope) when absent.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
@Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}
When you reference the above bean via #{someBean}
, it would return the Spring-managed application scoped bean, not the JSF-managed view scoped bean.
@ManagedProperty
vs @Autowired
The JSF-specific @ManagedProperty
works only in JSF-managed beans, i.e. when you're using @ManagedBean
. The Spring-specific @Autowired
works only in Spring-managed beans, i.e. when you're using @Controller
. Below approaches are less or more equivalent and cannot be mixed:
@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.
}
Do note that when you have the SpringBeanFacesELResolver
registered in faces-config.xml
as per the javadoc,
<application>
...
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
and thus you can reference Spring managed beans in EL via #{springBeanName}
, then you can just reference them in @ManagedProperty
too, as it basically sets the evaluated result of the given EL expression. The other way round, injecting a JSF managed bean via @Autowired
, is in no way supported. You can however use @Autowired
in a JSF managed bean when you manually register the JSF managed bean instance in Spring autowirable context like below. See also How to integrate JSF 2 and Spring 3 (or Spring 4) nicely for the trick.
@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's @Scope
has limited support for JSF scopes. There's no equivalent for JSF's @ViewScoped
. You'd basically either homegrow your own scopes, or stick to manually registering the JSF managed bean instance in Spring autowirable context as shown above.
And, from the other side on, Spring WebFlow was taken over in JSF 2.2 via new @FlowScoped
annotation. So if you happen to be on JSF 2.2 already, then you don't necessarily need to use Spring WebFlow if you solely want the flow scope.
CDI - trying to unify it all
Since Java EE 6, CDI is offered as standard alternative to Spring DI. It has respectively @Named
and @Inject
annotations for this and also its own set of scopes. I'm not sure how it interacts with Spring as I don't use Spring, but @Inject
works inside a @ManagedBean
, and @ManagedProperty
inside a @ManagedBean
can reference a @Named
bean. On the other hand, @ManagedProperty
doesn't work inside a @Named
bean.
The purpose of CDI is to unify all different bean management frameworks into only one specification/inteface. Spring could have been a full CDI implementation, but they choosed to only partially implement it (only JSR-330 javax.inject.*
is supported, but JSR-299 javax.enterprise.context.*
not). See also Will Spring support CDI? and this tutorial.
JSF will be moving to CDI for bean management and deprecate @ManagedBean
and friends in a future version.
See also:
- When is it necessary or convenient to use Spring or EJB3 or all of them together?
- JSF Service Layer
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
- Using JSF as view technology of Spring MVC
- How to install and use CDI on Tomcat?
这篇关于Spring JSF集成:如何在JSF管理的bean中注入Spring组件/服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!