8 août 2008
Imprimer ce billet

Simplifiez votre configuration Spring 2.5 avec les annotations

Spring 2.5 est sorti depuis le 19 novembre 2007 comme nous l'annoncions, il y a quelques temps, dans notre revue de presse. Vous avez comme moi sagement mis à jour vos poms Maven2 vers la dernière release de Spring (normalement et la plupart du temps compatible avec les versions 2.0.x). Mais avez-vous vraiment profité des nouveautés de cette version en terme de configuration ?

Les nouveautés Spring 2.5

Spring introduit plusieurs nouveautés concernant sa configuration, toutes les évolutions visant à la simplifier (ou à améliorer l'existant) :

  • Ajout de nouvelles balises basées sur les possibilités d'extension de schéma de Spring (Exemple : L'ajout des namespaces jms, context ou l'amélioration des namespaces jee, aop)
  • La création de JavaConfig
  • Le support des annotations Java 5, déjà amorcé dans Spring 2.0

Dans cet article, nous nous concentrerons sur les possibilités de configuration avec les annotations mais sans éviter un ou deux écarts :-) .

Configuration XML

Je vous parle d'annotations depuis le début de cet article, et le premier bout de code que je vous propose est en ... XML. Eh oui, la prise en compte par Spring des annotations se configure encore en XML.

Mais heureusement avec l'extension de schéma 'context', cette configuration est très simple. Il suffit d'ajouter deux balises : la première sert à ajouter un certain nombre de BeanPostProcessor (voir la documentation), la seconde à définir le ou les packages (séparés par des virgules) que Spring va devoir parcourir à la recherche de nos annotations.

<beans
    ...
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd"
>

    <context:annotation-config />
    <context:component-scan base-package="fr.xebia.demo.wicket.blog.service" />

</beans>

La balise <context:component-scan> n'est requise que si nous utilisons les annotations 'stéréotype' de Spring. Il est possible d'être plus directif sur la recherche d'annotations dans les classes comme le montre l'exemple ci-dessous.

<context:component-scan base-package="example" use-default-filters="false">
   <context:include-filter type="aspectj" expression="example..Stub*"/>
   <context:include-filter type="annotation" expression="example.Mock"/>
   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

Les stéréotypes Spring

Habituellement pour déclarer un bean géré par Spring, on devait ajouter une balise <bean name=...> dans notre fichier xml de configuration Spring. La balise <context:component-scan> vue précédemment indique à Spring qu'il doit rechercher dans le code certaines annotations que voici : @Repository, @Service, @Controller, @Component.

Ces annotations n'ont pas d'effet particulier sur l'injection de dépendances : elles servent entre autres à 'catégoriser' plus finement nos beans pour, en cas de besoin, appliquer des aspects plus facilement par la suite. Il faut voir ces annotations comme une bonne pratique à mettre en place pour donner du sens à nos beans.

  • @Repository : Cette annotation existe depuis Spring 2.0 et sert à identifier un bean de type DAO.
  • @Service : Celle-ci identifie le bean comme un service
  • @Controller : Utile uniquement si l'on utilise SpringMVC, cette annotation indique un contrôleur Spring MVC.
  • @Component : Cette dernière est l'annotation générique pouvant fonctionner pour n'importe quel bean

Autre avantage, Spring se sert de ces annotations pour appliquer lui aussi quelques aspects, comme par exemple, @Repository qui est pris en compte par Spring comme un marqueur pour la translation automatique d'exception pour la couche de persistance.

Voici un exemple très simple :

@Repository
public class ClientDAO {
    [...]
}

Chaque annotation prend un attribut 'name' optionnel qui peut être utilisé pour nommer explicitement le bean.

Ces annotations permettent de référencer nos beans dans le contexte d'application Spring pour qu'il puisse réaliser les injections de dépendances. Sans annotation, un bean n'est pas traité par Spring. Il existe une dernière annotation permettant de demander à Spring d'injecter des dépendances sur un bean qu'il ne gère pas : c'est l'annotation @Configurable. Spring ne va pas gérer le bean mais va quand même réaliser l'injection des dépendances sur celui-ci.

Pour modifier le cycle de vie de nos beans, il est aussi toujours possible de préciser le scope avec l'annotation du même nom : @Scope.

L'injection des dépendances

Nous venons de voir comment référencer nos beans dans le contexte d'application Spring. Nous allons étudier maintenant la façon de configurer l'injection de nos dépendances. Cela passe, bien sûr, par l'ajout de quelques annotations dans notre code. Il y a deux catégories d'annotations : les standards et les propriétaires Spring.

Le support de la JSR-250 et de JPA

La JSR-250 introduit plusieurs annotations permettant de déclarer un besoin d'injection de dépendances. Spring supporte l'annotation @Resource permettant la déclaration d'une ressource à injecter (cette annotation peut prendre l'attribut 'name' en paramètre). Dans la terminologie Spring, ce type d'injection est appelée 'by-name'. Pour déclarer une dépendance comme obligatoire, on ajoutera l'annotation @Required. Dans cette JSR, il existe deux autres annotations prises en charge par Spring : @PreConstruct et @PostDestroy qui remplace l'utilisation des interfaces InitializingBean et DisposableBean.

Ces annotations sont disponibles en standard dans le jdk6. Si vous utilisez le jdk5, vous devrez obtenir le jar à cet url ou si vous utilisez maven, la dépendance à ajouter est la suivante javax.annotation:jsr250-api:1.0.

JPA de son côté introduit lui aussi quelques annotations supportées par Spring : @PersistenceUnit qui permet l'injection d'un EntityManagerFactory et @PersistenceContext (ou @PersistentContext{+}s+) pour l'injection d'un EntityManager.

Les annotations spécifiques Spring

Spring permet aussi l'utilisation de l'annotation @Autowired qui lui est propre. Cette annotation fonctionne comme le @Resource sauf qu'ici Spring fera de l'injection 'by-type' c'est à dire en se basant sur la classe du bean à injecter. Il n'est ici pas possible de préciser un nom de bean explicitement. Il est par contre possible d'utiliser l'annotation @Qualifier pour permettre à Spring de choisir la bonne dépendance. Avec cette annotation on précise des qualifiers à la fois sur les beans managés et sur les attributs ou sur les méthodes où Spring doit injecter des dépendances : Spring trouvera le meilleur candidat à l'injection en s'aidant de ces qualifiers si besoin.

Pour déclarer une dépendance comme obligatoire, on utilisera l'attribut required de l'annotation @Autowired.

Pour faciliter le travail du transaction manager, l'annotation @Transactional peut être positionnée sur une classe ou sur les méthodes qui la composent pour préciser à Spring quelles méthodes doivent s'exécuter dans une transaction (sans oublier d'ajouter <tx:annotation-driven transaction-manager="txManager"/> avec votre fichier de configuration XML). L'annotation prend plusieurs attributs permettant de configurer le comportement transactionnel à appliquer.

A-t-on encore besoin de fichier XML ?

Avec l'introduction des annotations, a-t-on encore besoin de fichiers XML pour configurer Spring ? La réponse est bien sûr 'oui' puisqu'il reste nécessaire pour configurer la prise en compte des annotations. Cependant, ces annotations permettent de beaucoup simplifier et d'alléger le fichier de configuration. Seul le strict nécessaire subsistera : la configuration et la déclaration des ressources communes à tous les beans ainsi que la création des beans que nous ne développons pas (et donc sur lesquels nous ne pouvons pas positionner d'annotations).

Notamment, la configuration et l'utilisation d'AOP ainsi que la déclaration du transaction manager, d'Hibernate ou de JPA sont les éléments qui peuvent rester dans le fichier de configuration XML classique.

Ressources

Mots-clefs :,