2010-11-10 133 views
5

我想將一個在Spring上下文中定義的bean注入CDI託管組件,但是我不成功。該bean沒有被注入,而是每次執行注入時創建一個新的實例。我的環境是JBoss Weld的Tomcat 7。使用CDI注入Spring bean @Inject

Spring的ApplicationContext是簡單明瞭:

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

的CDI託管bean看起來是這樣的:

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

然而,當我訪問test來自JSF頁面的財產,新的每次訪問發生時都會創建實例。這是一個簡單的例子:

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

我得到以下輸出:

1: [email protected] 
2: [email protected] 

刷新後:

1: [email protected] 
2: [email protected] 

我可以看到第一個輸出是正確的。無論刷新頁面的頻率如何,testFromSpring都會返回Spring上下文中定義的bean的值。然而,第二個輸出清楚地表明,每當test組件的getTest方法被調用時,就會創建一個新的Test實例並注入,而不像我所期望的那樣使用Spring上下文中的實例。

那麼,這種行爲的原因是什麼?

如何從Spring上下文將bean注入到CDI託管bean中?

我也嘗試過使用使用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)] 

的代碼

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

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

這可能是缺少咖啡的原因,但爲什麼要注入一個私人成員(已經設置爲空)。將myTest作爲TestA構造函數的一部分提供(例如構造函數注入)並不簡單嗎? – 2010-11-10 12:07:57

+0

注入僅僅是一個例子,而不是問題的要點。 – perdian 2010-11-10 15:06:10

回答

12

帕斯卡是正確的,你不能注入一些由彈簧管理的東西到焊接bean(反之亦然)。

但是你可以定義一個生產者,獲取spring bean並將它們提供給Weld。這聽起來像是一個極端的黑客,順便說一句,我不認爲你應該在一個項目中使用這兩個框架。選擇一個並刪除其他。否則,你會遇到很多問題。

下面是它的樣子。

@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,並在春季環境中查找它。

+0

您無法生成Object並與CDI中的Foo注入點匹配 – kaos 2017-11-14 13:06:59

4

我不認爲Weld可以注入Weld沒有管理(實例化)的東西(在你的情況下是一個Spring bean)。