简体   繁体   English

使用CDI @Inject注入Spring bean

[英]Injecting a Spring bean using CDI @Inject

I'm trying to inject a bean defined in a Spring context into a CDI managed component but I'm not successful. 我正在尝试将Spring上下文中定义的bean注入CDI托管组件,但我没有成功。 The bean is not injected, instead a new instance gets created each time the injection should be performed. 不注入bean,而是每次执行注入时都会创建一个新实例。 My environment is Tomcat 7 with JBoss Weld. 我的环境是使用JBoss Weld的Tomcat 7。

The Spring ApplicationContext is straighforward: Spring ApplicationContext是直截了当的:

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

The CDI managed bean looks like this: CDI托管bean看起来像这样:

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

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

  ...

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

}

This is my faces-config.xml 这是我的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>

However, when I access the test property from within a JSF page, a new Test instance is being created each time the access occurs. 但是,当我从JSF页面访问test属性时,每次访问时都会创建一个新的Test实例。 This is a simple example: 这是一个简单的例子:

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

I get the following output: 我得到以下输出:

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

After a refresh: 刷新后:

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

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. 无论我多久刷新一次页面, testFromSpring返回Spring上下文中定义的bean的值。 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. 但是第二个输出清楚地表明,每次调用test组件上的getTest方法时,都会创建并注入一个新的Test实例,而不是像我期望的那样使用Spring上下文中的实例。

So, what's the reason for this behaviour? 那么,这种行为的原因是什么?

How can I inject the bean from the Spring context into the CDI managed bean? 如何将Spring上下文中的bean注入CDI托管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: 我也尝试使用在Spring上下文中定义的名称的限定符,但现在抛出一个异常,表明找不到bean:

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

for the code 代码

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

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

Pascal is right that you can't inject something managed by spring into a weld bean (or vice-versa). Pascal是对的,你不能将由spring管理的东西注入焊接豆(反之亦然)。

But you can define a producer that gets spring beans and gives them to Weld. 但是你可以定义一个生成器来获取spring bean并将它们提供给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. 否则你会遇到很多问题。

Here's how it would look like. 这是它的样子。

@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);
    }
}

Then you can have: 然后你可以:

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

PS You can make the above more type-safe. PS你可以使上面的类型更安全。 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. 您可以通过反射获得注入点的泛型类型,并在spring上下文中查找,而不是通过名称获取bean。

我不认为Weld可以注入一些未经Weld管理(实例化)的东西(在你的情况下是一个Spring bean)。

There's also the JBoss Snowdrop project. 还有JBoss Snowdrop项目。 I don't know if it'll work with JBoss Weld on Tomcat, the documentation describes only on JBoss 5, 6 and 7. According to http://docs.jboss.org/snowdrop/2.0.0.Final/html/ch03.html#d0e618 it will inject beans declared in jboss-spring.xml into locations marked with @Spring instead of @Inject. 我不知道它是否适用于Tomcat上的JBoss Weld,文档仅描述了JBoss 5,6和7.根据http://docs.jboss.org/snowdrop/2.0.0.Final/html/ ch03.html#d0e618它会将jboss-spring.xml中声明的bean注入到用@Spring而不是@Inject标记的位置。 No experience myself though, YMMV. 没有经验,YMMV。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM