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.
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
.
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")
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;
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;
_
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.
Pour Spring 2.5, il n'y a pas de @Primary
. Le seul moyen est d'utiliser @Qualifier
.
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.