web-dev-qa-db-fra.com

Guice injector.getInstance () - bonne pratique?

Disons que j'ai deux applications partageant la même bibliothèque. Cette bibliothèque contient des classes communes telles que DAO, Utils, etc. Tout dans la bibliothèque partagée est câblé avec Guice. Mes deux applications dépendent de cette bibliothèque, mais ne dépendent pas directement de Guice.

 ______    ______    ______
|      |  |      |  |      |
| APP1 |->| LIB  |<-| APP2 |
'------'  '------'  '------'

J'utilise actuellement quelque chose comme ça:

static <T> Utils.getInstanceOf (Class<T> type);

qui est simplement une enveloppe pour:

injector.getInstance (Class<T> type);

Mais la documentation de Guice dit:

Si possible, évitez d’utiliser cette méthode, mais préférez que Guice injecte vos dépendances à l’avance.

Alors quel est le meilleur moyen de fournir une injection de dépendance pour les deux applications sans avoir à les lier manuellement dans un module Guice?

14
albogdano

Quel est donc le meilleur moyen de fournir une injection de dépendance pour les deux applications Sans devoir les lier manuellement dans un module Guice?

Il n'y a pas de telle façon. Soit vous acceptez totalement Guice, soit vous ne l'utilisez pas et passez explicitement vos dépendances. Eh bien, structurer votre code de manière à ne jamais créer directement de dépendances de classe, en les passant à travers un constructeur, peut également être appelé «injection de dépendance», mais je suis sûr que ce n'est pas ce que vous vouliez dire. Si vous ne souhaitez pas utiliser Guice dans vos applications, vous ne pourrez rien obtenir de mieux que getInstance(), ce qui est moche, notamment parce que vous utilisez static wrapper.

Idéalement, votre bibliothèque devrait fournir un module que vous pouvez installer via Guice.createInjector() dans vos applications ou, à l'inverse, une bibliothèque Injector que vous pouvez utiliser dans vos applications en utilisant createChildInjector() et en fournissant des modules spécifiques à l'application. Une légère modification de cette approche consiste à transmettre des modules spécifiques à l'application à la bibliothèque afin qu'ils soient utilisés pour créer Injector. J'ai récemment écrit une API basée sur Guice sur une interface personnalisée de type servlet qui ne supportait aucun type de DI utilisant la dernière approche, et cela fonctionne parfaitement.

Il n’est pas du tout difficile d’utiliser Guice dans un environnement servlet ou Jersey. Ce dernier, par exemple, a une intégration prête à l'emploi avec Guice (au moins, dans les versions 1.x). Guice extension de servlet est également très bon et pratique. Essayez-le et voyez par vous-même.

9
Vladimir Matveev

static <T> Utils.getInstanceOf (Class<T> type);

Vous vous êtes retrouvé avec un Service Locator .

Bien que, dans quelques cas mineurs, il soit acceptable que injector s'échappe dans d'autres objets de création, je ne pense pas que ce soit l'un d'entre eux. Vous vous êtes retrouvé avec tous les inconvénients d'un localisateur de services et vous pouvez obtenir tous les avantages en utilisant l'outil que vous utilisez déjà.

3

Le modèle "habituel" d'utilisation d'un injecteur consiste à le configurer à un point d'entrée de niveau supérieur de votre projet (dans un scénario de servlet, à l'aide de Guice-Servlet, il s'agirait de GuiceServletContextListener). Vous souhaiterez peut-être configurer un injecteur individuel à un point d'entrée pour créer une dépendance et le rendre responsable du câblage de cette dépendance, dans un souci de modularisation. Si vous voulez les deux liaisons individuelles et les liaisons du projet parent, dans vos dépendances, vous pouvez créer un injecteur enfant qui délègue à son parent si aucune liaison n'est trouvée. Guice soutient cela.

Cependant, il me semble étrange que vous souhaitiez configurer un injecteur dans une dépendance et l’utiliser dans votre (vos) application (s) principale (s). Cela signifierait que la dépendance connaît toutes les liaisons requises par les applications principales. Je ne suis pas tout à fait sûr de ce que vous essayez d'atteindre avec cette approche. Est-ce que vos deux applications ont la même configuration/une configuration de liaison très similaire et vous ne voulez pas la répéter? Dans ce cas, vous devez définir un module avec toutes ces configurations de liaisons (une dépendance par exemple) et l'utiliser lors de la configuration de l'injecteur aux points d'entrée de chacune de vos applications. C'est beaucoup en ce qui concerne votre scénario.

Pour votre question en général. Je pense que sa bonne pratique pour éviter de dépasser explicitement l'injecteur. Chaque fois que vous faites cela, vous travaillez contre l'idée d'injection de dépendance en tant que projet transparent et vous vous attachez à un cadre d'injection concret. Dans la plupart des cas, vous pouvez éviter les références explicites à l'injecteur en utilisant Providers et Factories .

2
Sven Amann

Si vous avez une méthode qui doit créer une nouvelle instance de classe C au moment de l'exécution, associez un fournisseur à votre classe. C serait lié de la manière habituelle, par exemple.

public CModule extends AbstractModule {
    @Overide
    public void configure() {
        bind(C.class).to(CImpl.class);
    }
}

La classe qui crée les instances C ressemblerait à ceci:

class UserOfC {
    private Provider<C> cProvider;
    ...

    @Inject
    UserOfC(Provider<C> cProvider, ...) {
        this.cProvider = cProvider;
        ...
    }

    public void doSomethingWithAC (...) {
        C myC = cProvider.get();  // not a singleton; new instance created!
        ...
    }
}

Guice soutient l'injection de fournisseur gratuitement pour rien. Si C est lié, vous pouvez injecter un fournisseur aussi facilement que vous pouvez injecter une instance de C.

Suggestions supplémentaires:

Je vous recommande fortement d'injecter toutes les dépendances à la construction, dans la mesure du possible, même si cela nécessite l'écriture de quelques lignes de code supplémentaires. Cela fait des années que j'utilise Guice et je n'ai pas encore besoin d'une construction partielle ni d'aucune autre fonctionnalité avancée. 

Quand je suis confronté à la nécessité d'une injection partielle, j'écris généralement ma propre usine. Je trouve beaucoup plus facile à comprendre et à déboguer quand j'écris le code.

2
Eric Mintz

Ouais ça va passer l'injecteur de cette façon.

Même si nous avons fait quelque chose de similaire avec notre application de guichet, nous avons simplement utilisé injector.get.inject(this) et passé dans le constructeur pour les pages autres que le guichet.

et cela fonctionne parfaitement.

J'espère que cela t'aides.

0
Ashish