Published by

Il y a 14 ans -

Temps de lecture 3 minutes

Google Guice : Injection avancée

Dans le cadre d’un article d’introduction à Guice, nous avions vu une injection de dépendance simple, répondant à un besoin relativement basique.

Dans ce second article, nous allons découvrir des outils d’injection plus évolués, qui devraient nous permettre de réaliser par la suite notre premier exemple ‘réel’ d’implémentation Guice.

Injection ‘nommée’

Reprenons l’exemple simple utilisé dans l’article précédent pour en augmenter la difficulté.
Nous partons du postulat que notre DAO ne possède plus une seule, mais deux implémentations distinctes : MyBasicDaoImpl, précédemment utilisée, et MyBasicDaoMock, une nouvelle implémentation utilisant une base volatile.
Nous allons utiliser ces deux implémentations successivement dans notre service, et donc injecter deux implémentations différentes de la même interface dans notre service :

@Override
public void displaySample() {
	try {
		recorder.append("Calling DAOn");
		String daoResult = basicDao.select();
		recorder.append("Result from DAO : " + daoResult + "n");
		recorder.append("Calling memory DAOn");
		daoResult = memoryDao.select();
		recorder.append("Result from memory DAO : " + daoResult + "n");
	} catch (IOException e) {
		e.printStackTrace();
	}
}

Premier point à noter, pour notre DAO existant rien ne change, Guice utilisera la première implémentation déclarée pour résoudre la dépendance.
Pour notre seconde dépendance, nous utiliserons l’injection nommée.
Première solution, créer une annotation, @Memory, en utilisant la BindingAnnotation de Guice :

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Memory {}

Il suffit alors d’annoter le constructeur du service :

@Inject
public MyServiceImpl(MyBasicDao basicDao, @Memory MyBasicDao memoryDao) {
	super();
	this.basicDao = basicDao;
	this.memoryDao = memoryDao;
}

et d’annoter la déclaration de dépendance dans la classe Module

binder.bind(MyBasicDao.class).annotatedWith(Memory.class)
    .to(MyBasicDaoMemoryImpl.class);

Cette solution est relativement élégante, mais comporte le défaut de multiplier les classes d’annotation.
Le même résultat peut être atteint en utilisant une classe Guice permettant de nommer ses classes, mais sans créer d’annotation spécifique, à l’aide de l’annotation @Named et de la méthode Names.named(String)
Le code ci-dessus est équivalent à :

// Dans MyModule
binder.bind(MyBasicDao.class).annotatedWith(Names.named("Memory"))
    .to(MyBasicDaoMemoryImpl.class);

// Dans MyServiceImpl
@Inject
public MyServiceImpl(MyBasicDao basicDao, @Named("Memory") MyBasicDao memoryDao) {
    ...
}

Utiliser une dépendance conditionnelle à l’aide de l’annotation @Provides

Continuons à affiner notre injection de dépendance, en la conditionnant à des conditions runtime.
Imaginons que nous voulions injecter une implémentation de notre DAO en dépendant d’un paramètre runtime (nous nous baserons simplement sur un nombre aléatoire).
Pour cela, nous allons utiliser une méthode @Provides (à ne pas confondre avec les Providers de la version 1 de Guice).
Cette méthode doit être placée dans un module (où elle sera auto-découverte et retournera une instance de la classe injectée).

// Dans MyModule
/**
 * Provides method
 */
@Provides
@Inject
private @Named("Random")
MyBasicDao provideRandomDao(MyBasicDao basicDao,
		@Named("Memory") MyBasicDao memoryDao) {
	if (RandomUtils.randomBoolean()) {
		return basicDao;
	}
	return memoryDao;
}

On peut noter que cette méthode peut elle-même être injectée (avec les instances de Dao précédemment utilisées).

Conclusion

Nous avons maintenant une certaine souplesse dans l’injection, qui va nous permettre d’aborder dans un prochain billet un exemple plus concret.
À noter que durant la rédaction de ce billet, la version 2.0 de Google Guice a été officiellement releasée, et que les prochains billets se baseront sur cette version stable.

Téléchargez le projet Eclipse sur le Google Code de Xebia.

Published by

Publié par Pablo Lopez

Pablo est directeur technique chez Xebia et formateur Hadoop certifié par Cloudera au sein de Xebia Training .

Commentaire

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Sapient, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.