[JAVA] Comment utiliser InjectorHolder dans OpenAM

introduction

Cet article décrit comment l'injecteur Google Guice et son support d'injecteur constitutif sont utilisés dans OpenAM. Le code pertinent se trouve dans un package appelé Guice Core de ForgeRock. Le code source est ** ici ** Peut être référencé. Commençons par une explication de base de l'injecteur Guice.

Principes de base de l'injecteur Guice

C'est presque Noël / fin d'année, donc je vais vous expliquer en utilisant deux classes, ChristmasGreeting et NewYearGreeting, qui implémentent l'interface SeasonsGreeting.

Ce à quoi vous devez faire attention est la partie où la méthode Guice # createInjector (Module ...) obtient une instance de ʻInjector`.

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class Example01 {

    public interface SeasonsGreeting {
        void greeting();
    }

    public static class ChristmasGreeting implements SeasonsGreeting {
        @Override
        public void greeting() {
            System.out.println("Merry Christmas!");
        }
    }

    public static class NewYearGreeting implements SeasonsGreeting {
        @Override
        public void greeting() {
            System.out.println("Happy New Year!");
        }
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override protected void configure() {
                bind(SeasonsGreeting.class).to(ChristmasGreeting.class);
            }
        });

        SeasonsGreeting sg = injector.getInstance(SeasonsGreeting.class);
        sg.greeting();
    }
}

La méthode configure () connecte l'interface SeasonsGreeting avec son implémentation, ChristmasGreeting. L'injecteur généré en conséquence retournera une instance de "Christmas Greeting".

Résultat d'exécution


Merry Christmas!

Dans l'exemple ci-dessus, Guice # createInjector (Module ...) n'avait qu'un seul argument, mais il est possible de spécifier plusieurs arguments comme indiqué ci-dessous.

public static Injector createInjector(java.lang.Iterable<? extends Module> modules)

Avec cela, il est possible de lire plusieurs paramètres spécifiés dans une classe qui étend Module à la fois. Le InjectorHolder décrit ci-dessous fournit un "emplacement" fixe pour l'utilisation répétée de l'instance ʻInjector` créée de cette manière.

À propos du support d'injecteur

A partir du nom "Holder" de InjectorHolder, cela donne l'impression de sauvegarder l'instance générée de ʻInjector et de la retirer et de l'utiliser si nécessaire. Cependant, en réalité, ʻInjector est généré à l'intérieur de ʻInjectorHolder` et utilisé en interne. Cela peut être plus proche de la réalité si vous l'appelez un rappeur car vous ne serez pas éliminé.

Dans le code ci-dessous, le type d'énumération sort du début. Comment implémenter un singleton en utilisant une énumération avec un seul élément (ʻINSTANCE) Introduit dans l'élément 3 de [Effective Java 3rd Edition](https://www.amazon.co.jp/Effective-Java-%E7%AC%AC3%E7%89%88-Joshua-Bloch/dp/4621303252) Ça a été. Ici, nous l'utilisons pour définir ʻInjector Holder comme un singleton.

Notez la partie du constructeur privé qui utilise ʻInjectorFactory pour générer ʻInjector.


public enum InjectorHolder {

    /**
     * The Singleton instance of the InjectorHolder.
     */
    INSTANCE;

    private Injector injector;

    /**
     * Constructs an instance of the InjectorHolder and initialises the Guice Injector.
     */
    private InjectorHolder() {
        InjectorFactory injectorFactory = new InjectorFactory(new GuiceModuleCreator(),
                new GuiceInjectorCreator(), InjectorConfiguration.getGuiceModuleLoader());

        try {
            injector = injectorFactory.createInjector(InjectorConfiguration.getModuleAnnotation());
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalStateException(e);
        }
    }

    /**
     * @param clazz The class to get an instance of.
     * @param <T> The type of class to get.
     * @return A non-null instance of the class.
     */
    public static <T> T getInstance(Class<T> clazz) {
        return INSTANCE.injector.getInstance(clazz);
    }

La méthode finale getInstance (Class <T> clazz) retourne maintenant une instance du clazz créée en l'utilisant au lieu de renvoyer le singleton lui-même ou l'instance ʻInjector` enregistrée avec le singleton. Je suis.

Voyons maintenant comment ʻInjectorFactory crée une instance de ʻInjector.

À propos d'InjectorFactory

Comme mentionné précédemment, lors de la génération de ʻInjector, vous pouvez spécifier plusieurs instances d'une classe qui étend Module. Chaque classe d'extension remplace la méthode Configure ()` avec des paramètres différents. L'annotation «@ GuiceModule» est utilisée pour déterminer la classe d'extension à charger. Plus précisément, l'usine d'injecteurs

  1. Recherchez dans le chemin de classe la classe d'extension de Module annotée avec @ GuiceModule.
  2. Instanciez-les
  3. Passez comme argument à Guice # createInjector () pour générer ʻInjector`

Nous faisons le traitement. Le code ci-dessous est la partie introductive. Les autres parties sont omises car elles sont longues. Pour plus de détails, voir [Code public](https://github.com/openam-jp/forgerock-guice/blob/master/forgerock-guice-core/src/main/java/org/forgerock/guice/core/ Voir InjectorFactory.java).

final class InjectorFactory {

    /**
     * Creates a new Guice injector which is configured by all modules found by the {@link GuiceModuleLoader}
     * implementation.
     *
     * @param moduleAnnotation The module annotation.
     * @return A non-null Guice injector.
     */
    Injector createInjector(Class<? extends Annotation> moduleAnnotation) {
        /*
         This does not need to by synchronized as it is only ever called from the constructor of the
         InjectorHolder enum, which is thread-safe so no two threads can create an injector at the same time.

         This does mean that this method MUST not be called/used by another other class!
         */
        return injectorCreator.createInjector(createModules(moduleAnnotation));
    }

Nous avons vu comment fonctionne le porte-injecteur. Dans ce qui suit, nous verrons comment il est utilisé dans OpenAM.

Comment utiliser dans OpenAM

Le travail de rendre OpenAM compatible avec Google Guice a été fait il y a longtemps. De manière générale, rendre compatible avec Google Guice de gros logiciels comme OpenAM n'est pas facile. Vous commencerez avec un sous-arbre simple plus proche des branches et des feuilles de l'arborescence de dépendances, puis suivrez l'arborescence dans la direction d'objets plus complexes. Dans un arbre compliqué, il peut ne pas être possible de réécrire à la fois. Dans ce cas, placez l'InjectorHolder à la «frontière» entre la classe qui a été réécrite et la classe qui n'a pas été réécrite. Créez un objet de la classe réécrite à l'aide d'InjectorHolder dans la classe incomplète. La solution de la dépendance après cela est laissée à Google Guice. Au fur et à mesure que la réécriture progresse, le porte-injecteur se déplace également. En faisant cela, même un logiciel compliqué peut être réécrit progressivement.

En premier lieu, il peut ne pas être possible de prendre en charge Google Guice, ou il n'y a aucun mérite à le soutenir. Dans le cas d'OpenAM, il s'agit du service d'authentification. OpenAM dispose d'un mécanisme pour gérer indépendamment diverses instances de module d'authentification pour l'authentification multifacteur. Comme il est difficile de le rendre compatible avec Google Guice, InjectorHolder l'utilise au niveau des modules d'authentification individuels.

en conclusion

Chez OpenAM, nous avons vu que le porte-injecteur est placé à la «frontière» entre «non-Guice World» et «Guice World». Si vous êtes intéressé, veuillez consulter le Code source publié sur le Consortium OpenAM.

Recommended Posts

Comment utiliser InjectorHolder dans OpenAM
Comment utiliser Lombok au printemps
Comment utiliser les classes en Java?
Comment utiliser le volume nommé dans docker-compose.yml
Comment utiliser Docker dans VSCode DevContainer
Comment utiliser MySQL dans le didacticiel Rails
Comment utiliser les variables d'environnement dans RubyOnRails
Comprendre en 5 minutes !! Comment utiliser Docker
Comment utiliser credentials.yml.enc introduit à partir de Rails 5.2
Comment utiliser ExpandableListView dans Android Studio
Comment utiliser Map
Comment utiliser rbenv
Comment utiliser with_option
Comment utiliser fields_for
Comment utiliser java.util.logging
Comment utiliser la carte
Comment utiliser collection_select
Comment utiliser active_hash! !!
Comment utiliser MapStruct
Comment utiliser TreeSet
[Comment utiliser l'étiquette]
Comment utiliser l'identité
Comment utiliser le hachage
Comment utiliser Dozer.mapper
Comment utiliser Gradle
Comment utiliser org.immutables
Comment utiliser java.util.stream.Collector
Comment utiliser VisualVM
Comment utiliser Map
[Rails] Comment utiliser les boîtes de sélection dans Ransack
Comment utiliser JQuery dans Rails 6 js.erb
[Rails] Comment utiliser PostgreSQL dans l'environnement Vagrant
Comment utiliser l'API Chain
[Java] Comment utiliser Map
Comment utiliser Queue avec priorité
[Rails] Comment utiliser enum
Comment utiliser java Facultatif
Comment utiliser JUnit (débutant)
Comment utiliser le retour Ruby
[Rails] Comment utiliser enum
Comment utiliser @Builder (Lombok)
Comment utiliser Big Decimal
[Java] Comment utiliser removeAll ()
Comment utiliser String [] args
Comment utiliser Java Map
Ruby: Comment utiliser les cookies
Comment utiliser Dependant :: Destroy
Comment utiliser Eclipse Debug_Shell
Comment utiliser Apache POI
[Rails] Comment utiliser la validation
Comment utiliser les variables Java