[JAVA] Verwendung von InjectorHolder in OpenAM

Einführung

Dieser Artikel beschreibt, wie der Google Guice Injector und sein Bestandteil Injector Holder in OpenAM verwendet werden. Der entsprechende Code befindet sich in einem Paket namens Guice Core von ForgeRock. Der Quellcode lautet ** hier ** ) Kann referenziert werden. Beginnen wir mit einer grundlegenden Erklärung des Guice Injector.

Guice Injector Basics

Es ist fast Weihnachten / Jahresende, daher erkläre ich die Verwendung von zwei Klassen, "ChristmasGreeting" und "NewYearGreeting", die die "SeasonsGreeting" -Schnittstelle implementieren.

Was Sie beachten sollten, ist der Teil, in dem die Methode "Guice # createInjector (Module ...)" eine Instanz von "Injector" erhält.

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();
    }
}

Die Methode configure () verbindet die Schnittstelle SeasonsGreeting mit ihrer Implementierung ChristmasGreeting. Der entsprechend erzeugte "Injektor" gibt eine Instanz von "ChristmasGreeting" zurück.

Ausführungsergebnis


Merry Christmas!

Im obigen Beispiel hatte "Guice # createInjector (Module ...)" nur ein Argument, aber Sie können mehrere Argumente angeben, wie unten gezeigt.

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

Damit ist es möglich, mehrere Einstellungen zu lesen, die in einer Klasse angegeben sind, die "Modul" gleichzeitig erweitert. Der unten beschriebene InjectorHolder bietet einen festen "Platz" für die wiederholte Verwendung der auf diese Weise erstellten "Injector" -Instanz.

Über Injektorhalter

Aus dem Namen "Holder" von InjectorHolder geht hervor, dass die generierte Instanz von "Injector" gespeichert und herausgenommen und nach Bedarf verwendet werden soll. In der Realität wird "Injector" jedoch in "InjectorHolder" generiert und intern verwendet. Es kann näher an der Realität sein, wenn Sie es einen Rapper nennen, weil Sie nicht herausgenommen werden.

Im folgenden Code wird der Aufzählungstyp von Anfang an ausgegeben. So implementieren Sie einen Singleton mithilfe einer Aufzählung mit nur einem Element (INSTANCE) Eingeführt in Punkt 3 von Effective Java 3rd Edition Es ist gewesen. Hier verwenden wir es, um "InjectorHolder" als Singleton zu definieren.

Beachten Sie den Teil des privaten Konstruktors, der "InjectorFactory" verwendet, um "Injector" zu generieren.


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);
    }

Die endgültige Methode "getInstance (Class clazz)" gibt jetzt eine Instanz des damit erstellten "clazz" zurück, anstatt den Singleton selbst oder die beim Singleton registrierte "Injector" -Instanz zurückzugeben. Ich bin.

Nun wollen wir sehen, wie InjectorFactory eine Instanz von Injector erstellt.

Über InjectorFactory

Wie bereits erwähnt, können Sie beim Erstellen eines "Injectors" mehrere Instanzen einer Klasse angeben, die "Module" erweitert. Jede Erweiterungsklasse überschreibt die Configure () -Methode mit unterschiedlichen Einstellungen. Die Annotation "@ GuiceModule" wird verwendet, um zu bestimmen, welche Erweiterungsklasse geladen werden soll. Insbesondere die Injector Factory

  1. Durchsuchen Sie den Klassenpfad nach der Erweiterungsklasse von Module, die mit @ GuiceModule versehen ist.
  2. Instanziieren Sie sie
  3. Übergeben Sie als Argument an "Guice # createInjector ()", um "Injector" zu generieren

Wir machen die Verarbeitung. Der folgende Code ist der einleitende Teil. Andere Teile werden weggelassen, weil sie lang sind. Weitere Informationen finden Sie unter Öffentlicher Code. Siehe 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));
    }

Wir haben gesehen, wie der Injektorhalter funktioniert. Im Folgenden werden wir uns ansehen, wie es in OpenAM verwendet wird.

Verwendung in OpenAM

Die Arbeit, OpenAM mit Google Guice kompatibel zu machen, wurde vor langer Zeit durchgeführt. Im Allgemeinen ist es nicht einfach, große Software wie OpenAM mit Google Guice kompatibel zu machen. Sie beginnen mit einem einfachen Teilbaum, der näher an den Zweigen und Blättern des Abhängigkeitsbaums liegt, und folgen dem Baum dann in Richtung komplexerer Objekte. In einem komplizierten Baum ist es möglicherweise nicht möglich, sofort neu zu schreiben. Platzieren Sie in einem solchen Fall den InjectorHolder an der "Grenze" zwischen der Klasse, die neu geschrieben wurde, und der Klasse, die nicht neu geschrieben wurde. Erstellen Sie mit InjectorHolder in der unvollständigen Klasse ein Objekt der neu geschriebenen Klasse. Die Lösung der Abhängigkeit danach bleibt Google Guice überlassen. Während des Umschreibens bewegt sich auch der Injektorhalter. Auf diese Weise kann auch komplizierte Software schrittweise neu geschrieben werden.

Erstens ist es möglicherweise nicht möglich, Google Guice zu unterstützen, oder es gibt keinen Grund, es zu unterstützen. Bei OpenAM ist dies der Authentifizierungsdienst. OpenAM verfügt über einen Mechanismus zum unabhängigen Verwalten verschiedener Instanzen von Authentifizierungsmodulen für die Multi-Faktor-Authentifizierung. Da es schwierig ist, dies mit Google Guice kompatibel zu machen, verwendet Injector Holder es auf der Ebene einzelner Authentifizierungsmodule.

abschließend

Bei OpenAM haben wir gesehen, dass der Injektorhalter an der "Grenze" zwischen "Nicht-Guice-Welt" und "Guice-Welt" platziert ist. Wenn Sie interessiert sind, lesen Sie bitte den Quellcode, der im OpenAM-Konsortium veröffentlicht wurde.

Recommended Posts

Verwendung von InjectorHolder in OpenAM
Wie man Lombok im Frühling benutzt
Wie verwende ich Klassen in Java?
Verwendung des benannten Volumes in docker-compose.yml
Verwendung von Docker in VSCode DevContainer
Verwendung von MySQL im Rails-Tutorial
Verwendung von Umgebungsvariablen in RubyOnRails
Verstehe in 5 Minuten !! Wie man Docker benutzt
Verwendung von credentials.yml.enc aus Rails 5.2
Verwendung von ExpandableListView in Android Studio
Verwendung von Map
Wie benutzt man rbenv?
Verwendung mit_option
Verwendung von fields_for
Verwendung von java.util.logging
Verwendung der Karte
Verwendung von collection_select
Wie benutzt man active_hash! !!
Verwendung von MapStruct
Verwendung von TreeSet
[Verwendung des Etiketts]
Wie man Identität benutzt
Wie man Hash benutzt
Verwendung von Dozer.mapper
Wie benutzt man Gradle?
Verwendung von org.immutables
Verwendung von java.util.stream.Collector
Verwendung von VisualVM
Verwendung von Map
[Rails] Verwendung von Auswahlfeldern in Ransack
Verwendung von JQuery in Rails 6 js.erb
[Rails] Verwendung von PostgreSQL in einer Vagrant-Umgebung
Verwendung der Ketten-API
[Java] Verwendung von Map
Verwendung der Warteschlange mit Priorität
[Rails] Verwendung von Enum
Verwendung von Java Optional
Verwendung von JUnit (Anfänger)
Verwendung von Ruby return
[Rails] Verwendung von Enum
Verwendung von @Builder (Lombok)
Wie man Big Decimal benutzt
[Java] Verwendung von removeAll ()
Verwendung von String [] args
Verwendung von Java Map
Ruby: Wie man Cookies benutzt
Verwendung von abhängigen :: zerstören
Verwendung von Eclipse Debug_Shell
Verwendung von Apache POI
[Rails] Verwendung der Validierung
Verwendung von Java-Variablen