En utilisant deux beans implémentant la même interface – comment configurer automatiquement le bean par défaut?

Contexte:

J’ai une application Spring 2.5 / Java / Tomcat. Il y a le haricot suivant, qui est utilisé dans toute l’application dans de nombreux endroits

public class HibernateDeviceDao implements DeviceDao 

et le haricot suivant qui est nouveau:

 public class JdbcDeviceDao implements DeviceDao 

Le premier haricot est configuré de la sorte (tous les haricots du paquet sont inclus)

  

Le second bean (nouveau) est configuré séparément

    

Cela se produit (bien sûr) dans une exception lors du démarrage du serveur:

l’exception nestede est org.springframework.beans.factory.NoSuchBeanDefinitionException: aucun bean unique de type [com.sevenp.mobile.samplemgmt.service.dao.DeviceDao] n’est défini: bean correspondant unique attendu mais trouvé 2: [deviceDao, jdbcDeviceDao]

d’une classe essayant de créer le haricot comme ça

 @Autowired private DeviceDao hibernateDevicDao; 

car il y a deux beans implémentant la même interface.

La question:

Est-il possible de configurer les beans afin que

1. Je n’ai pas besoin de modifier les classes existantes, qui ont déjà HibernateDeviceDao automatiquement

2. être toujours capable d’utiliser le second (nouveau) bean comme ceci:

 @Autowired @Qualifier("jdbcDeviceDao") 

C’est-à-dire que j’aurais besoin d’un moyen de configurer le bean HibernateDeviceDao comme bean par défaut à générer automatiquement, en autorisant simultanément l’utilisation du JdbcDeviceDao lorsque cela est explicitement spécifié avec l’annotation @Qualifier .

Ce que j’ai déjà essayé:

J’ai essayé de mettre la propriété

 autowire-candidate="false" 

dans la configuration du bean pour JdbcDeviceDao:

    

parce que la documentation de spring dit que

Indique si ce haricot doit être pris en compte lors de la recherche de candidats correspondants pour satisfaire aux exigences de démarrage automatique d’un autre bean. Notez que cela n’affecte pas les références explicites par nom, qui seront résolues même si le bean spécifié n’est pas marqué comme candidat autowire. *

ce que j’ai interprété comme signifiant que je pouvais toujours envoyer JdbcDeviceDao à l’aide de l’annotation @Qualifier et utiliser le bean par défaut HibernateDeviceDao . Apparemment, mon interprétation n’était pas correcte, car cela entraîne le message d’erreur suivant au démarrage du serveur:

Dépendance non satisfaite de type [classe com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao]: au moins 1 bean correspondant attendu

venant de la classe où j’ai essayé de lancer le haricot avec un qualificatif:

 @Autowired @Qualifier("jdbcDeviceDao") 

Solution:

La suggestion de skaffman d’essayer l’annotation @Resource a fonctionné. Donc, la configuration a autowire-candidate définie sur false pour jdbcDeviceDao et lors de l’utilisation de jdbcDeviceDao, je m’en réfère à l’aide de l’annotation @Resource (au lieu de @Qualifier):

 @Resource(name = "jdbcDeviceDao") private JdbcDeviceListItemDao jdbcDeviceDao; 

    Je suggère de marquer la classe Hibernate DAO avec @Primary , c’est-à-dire (en supposant que vous ayez utilisé @Repository sur HibernateDeviceDao ):

     @Primary @Repository public class HibernateDeviceDao implements DeviceDao 

    De cette façon, il sera sélectionné comme candidat par défaut avec autowire, sans avoir besoin de autowire-candidate sur l’autre bean.

    En outre, plutôt que d’utiliser @Autowired @Qualifier , je trouve plus élégant d’utiliser @Resource pour choisir des beans spécifiques, c.-à-d.

     @Resource(name="jdbcDeviceDao") DeviceDao deviceDao; 

    Qu’en est-il de @Primary ?

    Indique qu’un bean doit avoir la préférence lorsque plusieurs candidats sont qualifiés pour générer automatiquement une dépendance à valeur unique. Si exactement un bean “principal” existe parmi les candidats, ce sera la valeur automatiquement. Cette annotation est sémantiquement équivalente à l’atsortingbut primary l’élément dans Spring XML.

     @Primary public class HibernateDeviceDao implements DeviceDao 

    Ou si vous souhaitez que votre version de Jdbc soit utilisée par défaut:

      

    @Primary est également idéal pour les tests d’intégration lorsque vous pouvez facilement remplacer le bean de production par une version stubed en l’annotant.

    Pour Spring 2.5, il n’y a pas de @Primary . Le seul moyen est d’utiliser @Qualifier .