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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18387993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 06:10:41  来源:igfitidea点击:

Spring JSF integration: how to inject a Spring component/service in JSF managed bean?

springjsfdependency-injectionintegrationmanaged-bean

提问by Ronaldo Lanhellas

I understand that a managed bean works like a controller, because your only task is "link" the View Layer with Model.

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

To use a bean as a managed bean I must declare @ManagedBeanannotation, doing that I can communicate JSF with bean directly.

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

If I want to inject some component (from Spring) in this managedBean I have two possibles ways:

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

  1. 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.

  2. Declared @Controller in ManagedBean Class, then i'll have @ManagedBeanand @Controllerannotations, all together. And in property "BasicDAO dao"i must use @Autowiredfrom Spring.

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

  2. 在 ManagedBean 类中声明 @Controller,然后我将拥有@ManagedBean@Controller注释,一起。在财产中,"BasicDAO dao"我必须@Autowired从 Spring使用。

Is my understanding correct?

我的理解正确吗?

采纳答案by tylerdurden

There is another way to use Spring-managed beans in JSF-managed beans by simply extending your JSF bean from SpringBeanAutowiringSupportand Spring will handle the dependency injection.

还有另一种在 JSF 管理的 bean 中使用 Spring 管理的 bean 的方法,只需扩展您的 JSF bean SpringBeanAutowiringSupport,Spring 将处理依赖项注入。

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

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

    // springBeanName is now available.
}

回答by BalusC

@ManagedBeanvs @Controller

@ManagedBean对比 @Controller

First of all, you should choose oneframework 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:

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

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

You end up with twocompletely 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 actuallybe used in EL when you reference it as #{someBean}. If you have the SpringBeanFacesELResolverregistered 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.

您最终会得到同一个托管 bean 类的两个完全独立的实例,一个由 JSF 管理,另一个由 Spring 管理。它不能直接清除哪一个会真正地在EL当你引用它作为使用#{someBean}。如果您已在 中SpringBeanFacesELResolver注册faces-config.xml,那么它将是 Spring 管理的,而不是 JSF 管理的。如果您没有它,那么它将是 JSF 管理的那个。

Also, when you declare a JSF managed bean specific scope, such as @RequestScoped, @ViewScoped, @SessionScopedor @ApplicationScopedfrom javax.faces.*package, it will only be recognized and used by @ManagedBean. It won't be understood by @Controlleras it expects its own @Scopeannotation. This defaults to singleton (application scope) when absent.

此外,当你宣布一个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 {}

When you reference the above bean via #{someBean}, it would return the Spring-managed application scoped bean, not the JSF-managed view scoped bean.

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



@ManagedPropertyvs @Autowired

@ManagedProperty对比 @Autowired

The JSF-specific @ManagedPropertyworks only in JSF-managed beans, i.e. when you're using @ManagedBean. The Spring-specific @Autowiredworks only in Spring-managed beans, i.e. when you're using @Controller. Below approaches are less or more equivalent and cannot be mixed:

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

Do note that when you have the SpringBeanFacesELResolverregistered in faces-config.xmlas per the javadoc,

请注意,当您按照javadocSpringBeanFacesELResolver注册时,faces-config.xml

<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 @ManagedPropertytoo, 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 @Autowiredin a JSF managed bean when you extend your bean from SpringBeanAutowiringSupport. This will automatically register the JSF managed bean instance in Spring autowirable context during constructor invocation, which means that everything @Autowiredwill be available in @PostConstructand later.

and thus you can reference Spring managed beans in EL via #{springBeanName}, then you can just reference them in @ManagedPropertytoo, 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 @Autowiredin a JSF managed bean when you extend your bean from SpringBeanAutowiringSupport. This will automatically register the JSF managed bean instance in Spring autowirable context during constructor invocation, which means that everything @Autowiredwill be available in @PostConstructand later.

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

Or when your architecture doesn't allow extending beans from a different base class, then you can always manually register the JSF managed bean instance in Spring autowirable context as below. See also How to integrate JSF 2 and Spring 3 (or Spring 4) nicelyfor the trick.

或者,当您的架构不允许从不同的基类扩展 bean 时,您始终可以在 Spring 自动装配上下文中手动注册 JSF 托管 bean 实例,如下所示。另请参阅如何很好地集成 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.
    }
}


@XxxScopedvs @Scope

@XxxScoped对比 @Scope

Spring's @Scopehas 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.

Spring@Scope对 JSF 范围的支持有限。JSF 的@ViewScoped. 您基本上要么自行开发自己的范围,要么坚持在 Spring 自动装配上下文中手动注册 JSF 托管 bean 实例,如上所示。

And, from the other side on, Spring WebFlow was taken over in JSF 2.2 via new @FlowScopedannotation. 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.

并且,从另一方面来说,Spring WebFlow 通过新的@FlowScoped注解在 JSF 2.2 中被接管。因此,如果您碰巧已经使用 JSF 2.2,那么如果您只需要流作用域,则不一定需要使用 Spring WebFlow。



CDI - trying to unify it all

CDI - 试图统一这一切

Since Java EE 6, CDI is offered as standard alternative to Spring DI. It has respectively @Namedand @Injectannotations 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 @Injectworks inside a @ManagedBean, and @ManagedPropertyinside a @ManagedBeancan reference a @Namedbean. On the other hand, @ManagedPropertydoesn't work inside a @Namedbean.

从 Java EE 6 开始,CDI 作为 Spring DI 的标准替代品提供。它分别有@Named@Inject对此的注释以及它自己的一组范围。我不确定它是如何与 Spring 交互的,因为我不使用 Spring,但@Inject在 a内部工作@ManagedBean,并且@ManagedProperty在 a 内部@ManagedBean可以引用一个@Namedbean。另一方面,@ManagedProperty@Namedbean 中不起作用。

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.

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

JSF will be moving to CDI for bean management and deprecate @ManagedBeanand friends in a future version.

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

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

See also:

也可以看看:

回答by hi.nitish

The easy way to do this is via XML. I used @Componentin already made jsf managed bean but @Autowireddid not work because managed bean was already there in faces-config.xml. If it is mandatory to keep that managed bean definition along with its managed property in the xml file then it is suggested to add the spring bean as another managed property inside the managed bean tag. Here the spring bean is there defined in spring-config.xml(can be autowired somewhere alternately). please refer https://stackoverflow.com/a/19904591/5620851

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

edited by me. I suggest to either implement it altogether through annotation @Managed and @Component or via xml for both.

由我编辑。我建议要么通过注释@Managed 和@Component 要么通过 xml 来实现它。