web-dev-qa-db-fra.com

Autowiring deux beans implémentant la même interface - comment définir le bean par défaut sur autowire?

Contexte:

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

public class HibernateDeviceDao implements DeviceDao

et le haricot suivant qui est nouveau:

public class JdbcDeviceDao implements DeviceDao

Le premier bean est configuré ainsi (tous les beans du paquet sont inclus)

<context:component-scan base-package="com.initech.service.dao.hibernate" />

Le deuxième (nouveau) bean est configuré séparément

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
    <property name="dataSource" ref="jdbcDataSource">
</bean>

Cela se traduit (bien entendu) par une exception lors du démarrage du serveur:

l'exception imbriquée est org.springframework.beans.factory.NoSuchBeanDefinitionException: aucun bean unique de type [com.sevenp.mobile.samplemgmt.service.dao.DeviceDao] n'est défini: un bean correspondant unique, mais il a trouvé 2: [deviceDao, jdbcDeviceDao]

d'une classe essayant d'autowire 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 de sorte que

1. Je n'ai pas à modifier les classes existantes, qui possèdent déjà le HibernateDeviceDao autowired

2. pouvant toujours utiliser le deuxième (nouveau) bean comme ceci:

@Autowired
@Qualifier("jdbcDeviceDao")

C'est à dire. J'aurais besoin d'un moyen de configurer le bean HibernateDeviceDao comme bean par défaut à être auto-câblé, permettant simultanément l'utilisation d'un JdbcDeviceDao lorsque explicitement spécifié ainsi 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:

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
    <property name="dataSource" ref="jdbcDataSource"/>
</bean>

parce que la documentation de Spring dit que

Indique si ce haricot doit ou non être pris en compte lors de la recherche de candidats correspondants pour satisfaire les exigences de câblage automatique d'un autre haricot. 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 utiliser le fil automatique JdbcDeviceDao en utilisant l’annotation @Qualifier et avoir le HibernateDeviceDao par défaut. Apparemment, mon interprétation n'était pas correcte, car cela entraîne le message d'erreur suivant lors du démarrage du serveur:

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

venant de la classe où j'ai essayé d'autowiring le haricot avec un qualificatif:

@Autowired
@Qualifier("jdbcDeviceDao")

Solution:

skaffman'ssuggestion d'essayer l'annotation @Resource a fonctionné. Donc, la configuration a autowire-candidat définie sur false pour jdbcDeviceDao et lorsque j'utilise jdbcDeviceDao, j'y fais référence en utilisant l'annotation @Resource (au lieu de @Qualifier):

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

Je suggérerais de marquer la classe DAO d'Hibernate avec @Primary , c'est-à-dire (en supposant que vous avez utilisé _@Repository_ sur HibernateDeviceDao):

_@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao
_

De cette façon, il sera sélectionné comme candidat par défaut pour le chemin automatique, sans qu'il soit nécessaire de _autowire-candidate_ sur l'autre bean.

De plus, plutôt que d’utiliser _@Autowired @Qualifier_, je trouve plus élégant d’utiliser _@Resource_ pour sélectionner des haricots spécifiques, c.-à-d.

_@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;
_
124
skaffman

Qu'en est-il de @Primary ?

Indique qu'une préférence doit être donnée à un bean lorsque plusieurs candidats sont qualifiés pour le transfert automatique d'une dépendance à valeur unique. S'il existe exactement un bean 'primaire' parmi les candidats, il s'agira de la valeur autowired. Cette annotation est sémantiquement équivalente à l'attribut primary de l'élément _<bean>_ dans Spring XML.

_@Primary
public class HibernateDeviceDao implements DeviceDao
_

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

_<bean id="jdbcDeviceDao" primary="true" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
_

_@Primary_ est également idéal pour les tests d'intégration, lorsque vous pouvez facilement remplacer un bean de production par une version avec stub en l'annotant.

36

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

8
blang
The use of @Qualifier will solve the issue.
Explained as below example : 
public interface PersonType {} // MasterInterface

@Component(value="1.2") 
public class Person implements  PersonType { //Bean implementing the interface
@Qualifier("1.2")
    public void setPerson(PersonType person) {
        this.person = person;
    }
}

@Component(value="1.5")
public class NewPerson implements  PersonType { 
@Qualifier("1.5")
    public void setNewPerson(PersonType newPerson) {
        this.newPerson = newPerson;
    }
}

Now get the application context object in any component class :

Object obj= BeanFactoryAnnotationUtils.qualifiedBeanOfType((ctx).getAutowireCapableBeanFactory(), PersonType.class, type);//type is the qualifier id

you can the object of class of which qualifier id is passed.
0
Sandeep Jain