web-dev-qa-db-fra.com

Intégration Spring JSF: comment injecter un composant / service Spring dans un bean géré JSF?

Je comprends qu'un bean géré fonctionne comme un contrôleur, car votre seule tâche est de "lier" la couche de vue au modèle.

Pour utiliser un bean en tant que bean géré, je dois déclarer l'annotation @ManagedBean, Ce qui me permet de communiquer directement JSF avec le bean.

Si je veux injecter un composant (de Spring) dans ce managedBean, j'ai deux façons possibles:

  1. Choisissez la propriété dans ManagedBean (comme "BasicDAO dao") et déclarez @ManagedProperty(#{"basicDAO"}) au-dessus de la propriété. Ce faisant, j'injecte le bean "basicDAO" De Spring dans ManagedBean.

  2. Déclaré @Controller dans la classe ManagedBean, alors j'aurai des annotations @ManagedBean Et @Controller, Tous ensemble. Et dans la propriété "BasicDAO dao" Je dois utiliser @Autowired De Spring.

Ma compréhension est-elle correcte?

39
RonaldoLanhellas

Il existe une autre façon d'utiliser les beans gérés par Spring dans les beans gérés par JSF en étendant simplement votre bean JSF à partir de SpringBeanAutowiringSupport et Spring gérera l'injection de dépendance.

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

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

    // springBeanName is now available.
}
8
tylerdurden

@ManagedBean Vs @Controller

Tout d'abord, vous devez choisir un framework pour gérer vos beans. Vous devez choisir JSF ou Spring (ou CDI) pour gérer vos beans. Bien que les travaux suivants fonctionnent, c'est fondamentalement faux:

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

Vous vous retrouvez avec deux instances complètement distinctes de la même classe de bean managé, une gérée par JSF et une autre gérée par Spring. Il n'est pas clair clairement lequel serait en fait utilisé dans EL lorsque vous le référencer comme #{someBean}. Si vous avez le SpringBeanFacesELResolver enregistré dans faces-config.xml, Alors ce sera celui géré par Spring, pas celui géré par JSF. Si vous ne l'avez pas, ce serait celui géré par JSF.

De plus, lorsque vous déclarez une portée spécifique au bean géré JSF, telle que @RequestScoped, @ViewScoped, @SessionScoped Ou @ApplicationScoped À partir du package javax.faces.*, il ne sera reconnu et utilisé que par @ManagedBean. Il ne sera pas compris par @Controller Car il attend sa propre annotation @Scope. Cette valeur par défaut est singleton (portée d'application) en cas d'absence.

@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
@Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}

Lorsque vous référencez le bean ci-dessus via #{someBean}, Il renvoie le bean de portée d'application géré par Spring, et non le bean de portée de vue géré par JSF.


@ManagedProperty Vs @Autowired

Le @ManagedProperty Spécifique à JSF ne fonctionne que dans les beans gérés par JSF, c'est-à-dire lorsque vous utilisez @ManagedBean. Le @Autowired Spécifique à Spring ne fonctionne que dans les beans gérés par Spring, c'est-à-dire lorsque vous utilisez @Controller. Les approches ci-dessous sont plus ou moins équivalentes et ne peuvent pas être mélangées:

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

Notez que lorsque vous avez le SpringBeanFacesELResolver enregistré dans faces-config.xml Selon le javadoc ,

<application>
    ...
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

et ainsi vous pouvez référencer les beans gérés par Spring dans EL via #{springBeanName}, alors vous pouvez aussi les référencer dans @ManagedProperty, car cela définit fondamentalement le résultat évalué de l'expression EL donnée. L'inverse, l'injection d'un bean géré JSF via @Autowired, N'est en aucun cas pris en charge. Vous pouvez cependant utiliser @Autowired Dans un bean géré JSF lorsque vous étendez votre bean de SpringBeanAutowiringSupport . Cela enregistrera automatiquement l'instance de bean géré JSF dans le contexte autowirable Spring lors de l'appel du constructeur, ce qui signifie que tout @Autowired Sera disponible dans @PostConstruct Et versions ultérieures.

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

Ou lorsque votre architecture ne permet pas d'étendre les beans à partir d'une classe de base différente, vous pouvez toujours enregistrer manuellement l'instance de bean géré JSF dans le contexte autoroutier Spring comme ci-dessous. Voir aussi Comment bien intégrer JSF 2 et Spring 3 (ou Spring 4) pour l'astuce.

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

@XxxScoped Vs @Scope

@Scope De Spring a un support limité pour les portées JSF. Il n'y a pas d'équivalent pour @ViewScoped De JSF. En gros, vous pouvez soit développer vos propres étendues, soit vous en tenir à enregistrer manuellement l'instance de bean géré JSF dans le contexte autoroutier de Spring, comme indiqué ci-dessus.

Et, de l'autre côté, Spring WebFlow a été repris dans JSF 2.2 via une nouvelle annotation @FlowScoped. Donc, si vous êtes déjà sur JSF 2.2, vous n'avez pas nécessairement besoin d'utiliser Spring WebFlow si vous voulez uniquement la portée du flux.


CDI - essayer de tout unifier

Depuis Java EE 6, CDI est proposé comme alternative standard à Spring DI. Il a respectivement @Named Et @Inject Annotations pour cela et aussi son propre ensemble de portées . Je ne sais pas comment il interagit avec Spring car je n'utilise pas Spring, mais @Inject Fonctionne dans un @ManagedBean Et @ManagedProperty Dans un @ManagedBean peut référencer un bean @Named. En revanche, @ManagedProperty ne fonctionne pas dans un bean @Named.

Le but de CDI est d'unifier tous les différents cadres de gestion de bean en une seule spécification/interface. Spring aurait pu être une implémentation CDI complète, mais ils ont choisi de ne l'implémenter que partiellement (seul JSR-330 javax.inject.* Est pris en charge, mais JSR-299 javax.enterprise.context.* Non). Voir aussi Spring supportera-t-il CDI? et ce tutoriel .

JSF passera à CDI pour la gestion des beans et dépréciera @ManagedBean Et ses amis dans une future version.

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

Voir également:

77
BalusC

Pour ce faire, le plus simple est via XML. J'ai utilisé @Component dans un bean géré jsf déjà fait mais @Autowired n'a pas fonctionné car le bean géré était déjà présent dans faces-config.xml. S'il est obligatoire de conserver cette définition de bean géré avec sa propriété managée dans le fichier xml, il est suggéré d'ajouter le bean spring comme autre propriété gérée à l'intérieur de la balise de bean managé. Ici, le bean de printemps est défini dans spring-config.xml (peut être câblé en alternance quelque part). veuillez vous référer https://stackoverflow.com/a/19904591/5620851

édité par moi. Je suggère de l'implémenter complètement via l'annotation @Managed et @Component ou via xml pour les deux.

1
hi.nitish