当前位置: 首页 > 知识库问答 >
问题:

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

苏边浩
2023-03-14

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

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

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

>

  • 选择ManagedBean中的属性(如“basicdao dao”)并在该属性上方声明@managedproperty(#{“basicdao”})。为此,我在ManagedBean中注入了Spring中的bean“basicdao”

    我的理解正确吗?

  • 共有1个答案

    卞经业
    2023-03-14

    首先,您应该选择一个框架来管理您的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管理的。如果您没有,那么它将是JSF管理的。

    此外,当您声明特定于JSF托管bean的作用域时,例如@requestscoped@viewscoped@sessionscoped@applicationscopedfromjavax.faces.*包,它只能被@managedbean识别和使用。@controller无法理解它,因为它需要自己的@scope注释。缺省时,这默认为singleton(应用程序范围)。

    @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。

    特定于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.
    }
    

    请注意,当您按照javadoc在faces-config.xml中注册了SpringBeanFaceselResolver时,

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

    因此,您可以通过#{springBeanName}在EL中引用Spring托管bean,然后也可以在@managedproperty中引用它们,因为它基本上设置了给定EL表达式的计算结果。另一方面,不支持通过@autowired注入JSF托管bean。但是,当您从SpringBeanAutowiringSupport扩展bean时,可以在JSF托管bean中使用@autowired。这将在构造函数调用期间在Spring autowirable上下文中自动注册JSF托管bean实例,这意味着@autowired中的所有内容都将在@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实例,如下所示。另请参见如何很好地集成JSF2和Spring3(或Spring4)。

    @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.
        }
    }
    

    Spring的@scope对JSF作用域的支持有限。JSF的@viewscoped没有等效的。基本上,您要么自行开发自己的作用域,要么坚持在Spring autowirable上下文中手动注册JSF托管bean实例,如上所示。

    另一方面,Spring WebFlow通过新的@flowscoped注释在JSF2.2中被接管。因此,如果您碰巧已经使用了JSF2.2,那么如果您只想要流作用域,就不一定需要使用Spring WebFlow。

    从Java EE6开始,CDI就作为Spring DI的标准替代品提供了。它对此分别有@named@inject注释,还有自己的作用域集。我不知道它如何与Spring交互,因为我不使用Spring,但是@inject@managedbean内部工作,而@managedbean内部的@managedproperty可以引用@namedbean。另一方面,@ManagedProperty不能在@namedbean中工作。

    CDI的目的是将所有不同的bean管理框架统一到一个规范/InteFace中。Spring本可以是一个完整的CDI实现,但他们选择只部分实现它(只支持JSR-330javax.inject.*,但不支持JSR-299javax.enterprise.context.*)。另见Spring会支持CDI吗?而这个教程。

    JSF将转向CDI进行bean管理,并在未来的版本中反对@managedbean和friends。

    @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.
        }
    }
    
    • 何时有必要或方便使用Spring或EJB3或它们一起使用?
    • JSF服务层
    • 支持beans(@managedbean)还是CDI beans(@named)?
    • 使用JSF作为Spring MVC的视图技术
    • 如何在Tomcat上安装和使用CDI?
     类似资料:
    • 问题内容: 我了解托管bean的工作方式类似于控制器,因为你的唯一任务是将“视图层”与模型“链接”。 要将bean用作托管bean,我必须声明注释,这样我就可以直接与bean通信JSF。 如果要在此managedBean中注入某些组件(来自Spring),则有两种可能的方法: 在ManagedBean中选择属性(例如“ BasicDAO dao”),然后在该属性上方进行声明。这样做,我是将”bas

    • 问题内容: 我正在使用框架JSF 2.1,Spring 3.1.1.Release,Hibernate 3.2.1进行Java EE项目。现在我正处于整合这三个方面的阶段。构建成功,我使用了tomcat服务器7。但是我在首页上看到了这个异常。 hibernatehibernate.cfg.xml hibernate.reveng.xml AnneeDao.java AnneeHibernateDa

    • 我在演示应用程序中使用了JSF2+Spring3.1+Hibernate4,我想使用注释来创建会话工厂,但是我的DAO类没有在Jsf托管Bea类中初始化,所以我得到了空指针异常。我的ApplicationContext.xml 现在,在Managedbean方法中,DAO对象为null,我得到的是null指针异常

    • 主要内容:实例,运行测试结果以下代码显示了如何进行bean注入。 我们先定义一个消息bean,它有一个字符串属性来存储消息。 然后我们再定义另一个托管bean,并使用注解注入。 实例 打开 NetBean8.2,创建一个名为: InjectManagedBeans 的工程,并加入以下文件代码。 以下是文件:UserBean.java 中的代码 - 以下是是文件:index.xhtml 中的代码 - 以下是文件:Message

    • 通常,如果我必须在Spring中注入服务,我会使用 和

    • 我正在开发一个遗留的JSF应用程序,我们正在慢慢地将其移植到Spring MVC。我们正在使用Spring Security来控制登录信息。在用户登录之后,JSF页面全局地实例化一个在任何地方都使用的会话作用域bean。我想更改应用程序,这样我们就可以先进入用Spring MVC开发的页面。 我尝试的一种方法是将bean转换为spring bean,并将其注入JSF,但不幸的是,这需要对bean进