使用 CDI @Inject 注入 Spring bean [英] Injecting a Spring bean using CDI @Inject

查看:27
本文介绍了使用 CDI @Inject 注入 Spring bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 Spring 上下文中定义的 bean 注入 CDI 托管组件,但没有成功.bean 没有被注入,而是在每次应该执行注入时创建一个新实例.我的环境是带有 JBoss Weld 的 Tomcat 7.

I'm trying to inject a bean defined in a Spring context into a CDI managed component but I'm not successful. The bean is not injected, instead a new instance gets created each time the injection should be performed. My environment is Tomcat 7 with JBoss Weld.

Spring ApplicationContext 很简单:

The Spring ApplicationContext is straighforward:

<beans>
  ...
  <bean id="testFromSpring" class="test.Test" />
  ...
</bean>

CDI 托管 bean 如下所示:

The CDI managed bean looks like this:

@javax.inject.Named("testA")
public class TestA {

  @javax.inject.Inject
  private Test myTest = null;

  ...

  public Test getTest() {
    return this.myTest;
  }

}

这是我的faces-config.xml

<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0">
  <application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
  </application>
</faces-config>

但是,当我从 JSF 页面中访问 test 属性时,每次发生访问时都会创建一个新的 Test 实例.这是一个简单的例子:

However, when I access the test property from within a JSF page, a new Test instance is being created each time the access occurs. This is a simple example:

<html>
  ...
  <p>1: <h:outputText value="#{testFromSpring}" /></p>
  <p>2: <h:outputText value="#{testA.test}" /></p>
  ...

我得到以下输出:

1: test.Test@44d79c75
2: test.Test@53f336eb

刷新后:

1: test.Test@44d79c75
2: test.Test@89f2ac63

我可以看到第一个输出是正确的.无论我多久刷新一次页面,testFromSpring 都会返回 Spring 上下文中定义的 bean 的值.然而,第二个输出清楚地表明,每次调用 test 组件上的 getTest 方法时,都会创建并注入一个新的 Test 实例而不是如我所料,使用 Spring 上下文中的实例.

I can see that the first output is correct. No matter how often I refresh the page, the testFromSpring returns the value from the bean defined in the Spring context. However the second output clearly shows that each time the getTest method on the test components is invoked, a new Test instance is created and injected instead of using the instance from the Spring context as I would expect.

那么,这种行为的原因是什么?

So, what's the reason for this behaviour?

如何将 Spring 上下文中的 bean 注入 CDI 托管 bean?

How can I inject the bean from the Spring context into the CDI managed bean?

我还尝试使用在 Spring 上下文中定义的名称使用限定符,但现在抛出异常,指示无法找到 bean:

I also tried using a qualifier using the name defined in the Spring context, but now an exception is thrown indicating, that the bean cannot be found:

org.jboss.weld.exceptions.DeploymentException: WELD-001408 Injection point has unsatisfied dependencies.  Injection point:  field test.TestA.myTest;  Qualifiers:  [@javax.inject.Named(value=testFromSpring)]

代码

@javax.inject.Named("testA")
public class TestA {

  @javax.inject.Inject
  @javax.inject.Named("testFromSpring")
  private Test myTest = null;

推荐答案

Pascal 是对的,你不能将 Spring 管理的东西注入到焊接 bean 中(反之亦然).

Pascal is right that you can't inject something managed by spring into a weld bean (or vice-versa).

但是您可以定义一个生产者来获取 spring bean 并将它们提供给 Weld.这听起来像是一个极端的黑客,顺便说一句,我认为您不应该在一个项目中同时使用这两个框架.选择一个并删除另一个.否则你会遇到很多问题.

But you can define a producer that gets spring beans and gives them to Weld. This sounds like an extreme hack, btw, and I don't think you are supposed to use both frameworks in one project. Choose one and remove the other. Otherwise you'll get in multiple problems.

这就是它的样子.

@Qualifier
@Retention(Runtime)
public @interface SpringBean {
     @NonBinding String name();
}


public class SpringBeanProducer {

    @Produces @SpringBean
    public Object create(InjectionPoint ip) {
         // get the name() from the annotation on the injection point
         String springBeanName = ip.getAnnotations()....

         //get the ServletContext from the FacesContext
         ServletContext ctx = FacesContext.getCurrentInstance()... 

         return WebApplicationContextUtils
              .getRequiredWebApplication(ctx).getBean(springBeanName);
    }
}

然后你可以:

@Inject @SpringBean("fooBean")
private Foo yourObject;

附言您可以使上述更类型安全.您可以通过反射获取注入点的泛型类型,而不是通过名称获取 bean,并在 spring 上下文中查找.

P.S. You can make the above more type-safe. Instead of getting the bean by name, you can get, through reflection, the generic type of the injection point, and look it up in the spring context.

这篇关于使用 CDI @Inject 注入 Spring bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆