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.
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.
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
.
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
Module
annotée avec @ GuiceModule
.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.
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.
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