PREMIERE PARTIE: Annotations Spring @Autowired, @Service & cie
Dans cette première partie, le projet java exemple ci-après n'utilise que les annotations de Spring.
Pré-requis:
Le projet java standard doit avoir les librairies nécessaires suivantes : spring-2.5.6.jar, spring-test-2.5.6.jar et Junit 4.4.jar ( apache-commons-**.jar).
Notez qu'il faudrait observer ces versions pour contourner un bug connu. Aussi, ne laissez pas eclipse choisir pour vous la librairie JUnit4 à ajouter dans le classpath du projet.
Configuration de Spring
Un fichier de Spring très léger nommé "spring-context.xml" qui contient ces deux lignes:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-autowire="byName"> <context:component-scan base-package="fr.netapsys.exemple.dao"/> <context:component-scan base-package="fr.netapsys.exemple.service"/> </beans>
Les classes java du projet sont ordinaires bien que les différentes couches sont bien séparées.
Couche entités
//la classe Entreprise package fr.netapsys.exemple.entites; public class Entreprise implements Serializable{ private int id; private boolean etat; public void setEtat(boolean etat){ this.etat=etat; } public boolean isEtat(){ return etat;} //autres setters/getters ......omis public String toString(){ return "Entreprise (id="+id+" etat="+etat+")"; } }
Couche DAO
L'interface:
package fr.netapsys.exemple.dao; public interface IEntrepriseDao{ boolean createEntreprise(Entreprise e); }
Notez l'annotation @Repository pour indiquer à Spring que cette classe appartient à la couche DAO.
Et l'implémentation donne:
package fr.netapsys.exemple.dao; @Repository("entrepriseDao") public class EntrepriseDao implements IEntrepriseDao{ public boolean createEntreprise(Entreprise entrep){ //do something... System.out.println("creating in dao "); return true; } }
Couche service
L'interface:
package fr.netapsys.exemple.service; public interface IEntrepriseService{ boolean createEntrerpise(Entrerpise entrep); }
L'implémentation:
package fr.netapsys.exemple.service; @Service("entrepriseService") public class EntrepriseService{ private IEntrepriseDao entrepriseDao; @Autowired public setEntrepriseDao() public boolean createEntreprise(Entreprise entrep){ return entrepriseDao.createEntreprise(entreprise); } }
Notez l'annotation @Autowired sur le setter de l'attribut entrepriseDao.
Ajoutons une classe de JUnit 4.4 nommée TestAnnotations.java qui contient ceci:
package fr.netapsys.exemple.tests; /*****imports omis*****/ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring-context.xml"}) public class TestAnnotationsSpring { private IEntrepriseService service; @Autowired public void setEntrepriseService(IEntrepriseService entrep){ this.service=entrep; } @Test public void test1(){ Entreprise entrep=new Entreprise(); entrep.setId(1); boolean retour=service.createEntreprise(entrep); Assert.assertTrue(retour); } }
Observez l'annotation @RunWith de JUnit4 et celle de @ContextConfiguration de Spring.
Elles permettent d'exécuter ce test JUnit en laissant à Spring le soin de charger son contexte à partir des fichiers mentionnés dans locations.
L'exécution de ce test dans eclipse, clic-droit, run as Junit Test, donne le résultat :
OK, tout cela fonctionne bien.
Mais si on rajoute une nouvelle classe de service, nommée EntrepriseServiceImpl2 dans la trace ci-dessous, qui implémente l'interface IEntrepriseService, notre test JUnit cesse de fonctionner!!!!
Et on obtient une "BeanCreationException" dont la trace est donnée ci-dessous:
''Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire method:
public void fr.netapsys.exemples.tests.TestAnnotationsSpring.setEntrepriseService(fr.netapsys.exemple.service.IEntrepriseService); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type
fr.netapsys.exemple.service.IEntrepriseService is defined: expected single matching bean but found 2: entrepriseService, entrepriseServiceImpl2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues ............ ......... Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type fr.netapsys.exemple.service.IEntrep... is defined:
expected single matching bean but found 2: entrepriseService, entrepriseServiceImpl2
''
Pourquoi donc? Et comment contourner cela?
La seconde partie de ce billet donne avec détails la réponse à ces deux questions.
Commentaires
Bonjour,
Ou se trouve la seconde partie du billet...?
SVP, le second billet !!
tout ça pour ça? Ou est la seconde partie?