2010-11-10 30 views
5

J'essaie d'injecter un bean défini dans un contexte Spring dans un composant géré par CDI, mais je ne réussis pas. Le bean n'est pas injecté, une nouvelle instance est créée à chaque fois que l'injection doit être effectuée. Mon environnement est Tomcat 7 avec JBoss Weld.Injection d'un bean Spring à l'aide de CDI @Inject

Le printemps ApplicationContext est straighforward:

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

Le CDI a réussi ressemble haricot ceci:

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

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

    ... 

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

} 

Ceci est mon 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> 

Cependant, quand j'accéder à la test propriété à partir d'une page JSF, un nouveau Test L'instance est créée chaque fois que l'accès se produit. Ceci est un exemple simple:

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

Je reçois la sortie suivante:

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

Après un rafraichissement

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

Je vois que la première sortie est correcte. Peu importe la fréquence d'actualisation de la page, la valeur testFromSpring renvoie la valeur du bean défini dans le contexte Spring. Cependant, la deuxième sortie montre clairement qu'à chaque fois que la méthode getTest sur les composants test est invoquée, une nouvelle instance Test est créée et injectée au lieu d'utiliser l'instance du contexte Spring comme je m'y attendais.

Alors, quelle est la raison de ce comportement?

Comment puis-je injecter le bean à partir du contexte Spring dans le bean géré par CDI?

J'ai aussi essayé d'utiliser un qualificatif en utilisant le nom défini dans le contexte du printemps, mais maintenant une exception est levée indiquant que le haricot ne peut pas être trouvé:

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

pour le code

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

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

Cela pourrait être un manque de café ici, mais pourquoi injecter un membre privé de votre classe (qui est déjà mis à null). Ne serait-il pas plus simple de fournir myTest dans le cadre du constructeur de TestA (par exemple, l'injection du constructeur) –

+0

L'injection est juste un exemple et non le point de la question. – perdian

Répondre

12

Pascal a raison de dire que vous ne pouvez pas injecter quelque chose géré par le ressort dans un haricot de soudure (ou vice-versa).

Mais vous pouvez définir un producteur qui obtient des haricots de printemps et les donne à Weld. Cela ressemble à un hack extrême, btw, et je ne pense pas que vous êtes censé utiliser les deux cadres dans un projet. Choisissez-en un et supprimez l'autre. Sinon, vous aurez de multiples problèmes.

Voici à quoi cela ressemblerait.

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

Ensuite, vous pouvez:

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

post-scriptum Vous pouvez faire ce qui précède plus de type sécurisé. Au lieu d'obtenir le nom du haricot, vous pouvez obtenir, par réflexion, le type générique du point d'injection, et le chercher dans le contexte du printemps.

+0

Vous ne pouvez pas produire d'objet et correspondre au point d'injection Foo dans CDI – kaos

4

Je ne pense pas que Weld puisse injecter quelque chose qui n'est pas géré (instancié) par Weld (un haricot de printemps dans votre cas).

2

Il y a aussi le projet JBoss Snowdrop. Je ne sais pas si cela fonctionnera avec JBoss Weld sur Tomcat, la documentation ne décrit que sur JBoss 5, 6 et 7. Selon http://docs.jboss.org/snowdrop/2.0.0.Final/html/ch03.html#d0e618, il va injecter les beans déclarés dans jboss-spring.xml dans les endroits marqués avec @Spring au lieu de @Injecter. Aucune expérience moi-même cependant, YMMV.