Comparaison Google Guice et Spring
Tout d'abord il faut préciser une petite chose : le périmètre fonctionnel des deux frameworks est totalement différent :
Spring est un framework qui entend couvrir l'ensemble des problématiques allant de la simple application CRUD à l'application d'entreprise :
- Injection de dépendances (Spring Core)
- Programmation orientée aspect, Transactions déclaratives (Spring Core & Spring AOP)
- Couche d'abstraction des framework ORM, proposant des Templates (méthodes CRUD, Finders,etc...) et exceptions typées selon le code retour de la base de données (Spring DAO)
- Composants permettant l'utilisation de JMS, JMX, WebServices, Scheduling (Spring JEE)
- Technologie de présentation MVC (Spring Web, Spring Web Flow...)
Google Guice couvre principalement l'injection de dépendances (également l'AOP, mais cela reste assez basique). C'est donc sur l'IoC qu'il est opportun d'effectuer une comparaison avec Spring.
Google Guice s'appuie principalement sur les fonctionnalités de JAVA 5, et plus précisément sur les annotations pour la configuration.
Les principaux reproches fait à Spring concernent la configuration, principalement sur les fichiers XML qui deviennent complexes et difficiles à maintenir dès lors que l'application devient conséquente. Même avec la version 2, sortie tout récemment, Spring n'a pas véritablement simplifié cette configuration qui reste basée sur du XML.
Injection de dépendances
Avec Spring
Je configure l'implémentation à utiliser dans mon fichier de configuration.
Dans le cas de tests unitaires, je vais avoir autant de configuration XML à écrire que de MockObjects à utiliser pour chaque cas de test
Dans l'exemple ci-dessous, je spécifie que je vais injecter la dépendance CustomerDAOImpl
dans customerService
Avec Google Guice
Je définis directement avec du code l'implémentation à utiliser.
Cette déclaration est réalisée dans le set up de mon test unitaire, ou dans le bootstrap de mon application.
protected void configure() { bind(CustomerDAO.class) .to(CustomerDAOMockImpl.class) .in(Scopes.SINGLETON); }
Je spécifie la dépendance à l'aide d'une annotation sur le setter ou le constructeur de ma classe CustomerService
public class CustomerService { private CustomerDAO customerDAO; // ... @Inject public void setCustomerDAO(CustomerDAO customerDAO) { this.customerDAO = customerDAO; } }
Je trouve cette approche avantageuse, le test unitaire est auto-portant : Je n'ai pas à switcher entre mon code et mon fichier XML pour configurer et vérifier si j'ai injecté linjecte le bon Mock en cas de problème...
Programmation Orienté Aspect
Prenons le cas d'un aspect Log que nous souhaitons appliquer sur les méthodes critiques de notre application à des fins d'audit.
Avec Spring
Je définis les endroits où je désire appliquer mon Aspect en spéficiant le Point de jonction (PointCut), présenté ci-dessus. Dans cet exemple, l'aspect octoLog
est appliqué sur l'ensemble des méthodes des implémentations. (L'expression régulière : (*xxx.*Impl.*(..))
spécifie les classes finissant par Impl du package xxx)
Avec Google Guice
Je crée une annotation qui définit l'aspect, je spécifie sur quel type d'élément cette annotation peut être appliquée (Classe, Méthode, Attribut...)
`@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @BindingAnnotation public @interface OctoLog {}`
J'applique l'annotation sur les méthodes/classes concernées. Si l'annotation est mal placée, l'IDE lève une erreur. Il s'agit du même mécanisme qu'avec les DTD/XML, mais dans le code.
public class CustomerDAOImpl implements CustomerDAO { @OctoLog public Customer getCustomerById(int id) { } }
Dans le bootstrap de mon application, j'ajoute la ligne de code suivante qui définit l'aspect à utiliser pour l'annotation OctoLog
:
bindInterceptor(any(),annotatedWith(OctoLog.class), new OctoLogger());
Je pense que l'utilisation des annotations pour la configuration est plus productive pour les raisons suivantes :
- Vérification et validation de la configuration (par l'IDE, auto-compilation)
- Auto-complétion disponible (Une annotation est une classe Java, la configuration de l'application s'effectue par du code...)
- Support du refactoring (Le renommage d'implémentation, d'annotations, d'interface s'applique également dans le code de configuration)
Du point de vu développeur, il me semble que c'est plus avantageux de positionner des annotations sur des méthodes et définir les implementation à utiliser par du code, plutôt que de se prendre la tête sur la configuration XML à la Spring... après, c'est une question de préférences...
Personnelement, j'aime bien savoir que ma configuration est valide pendant que je code plutôt que de le savoir à posteriori, lors de l'exécution de mon test-unitaire / application.
Dans un contexte où seule l'injection de dépendance est requise, je prendrais Google Guice, c'est light, c'est performant (les benchmarks montrent que l'initialisation d'une appli est 4 fois plus rapide avec Google Guice que Spring...), et surtout beaucoup plus simple pour la conf des tests unitaires... Il s'agit de la première release de Google, à suivre donc...