You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2022/07/23 23:40:38 UTC

[logging-log4j2] 01/02: Add more docs for plugins/DI

This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f92a61242211ab496e9542bbbb9d1681ef0a9d9d
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Sat Jul 23 18:00:27 2022 -0500

    Add more docs for plugins/DI
    
    Signed-off-by: Matt Sicker <ma...@apache.org>
---
 log4j-plugins/src/main/java/module-info.java       |  8 +++--
 .../logging/log4j/plugins/di/DefaultInjector.java  |  5 ++-
 .../apache/logging/log4j/plugins/di/Injector.java  | 40 ++++++++++++++++++----
 .../org/apache/logging/log4j/plugins/di/Key.java   | 15 +++++++-
 4 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/log4j-plugins/src/main/java/module-info.java b/log4j-plugins/src/main/java/module-info.java
index b884b96944..96e35e9476 100644
--- a/log4j-plugins/src/main/java/module-info.java
+++ b/log4j-plugins/src/main/java/module-info.java
@@ -16,12 +16,16 @@
  */
 
 /**
- * Log4j plugin annotations and dependency injection system.
+ * Log4j plugin annotations and dependency injection system. Plugins encompass a variety of customizable
+ * Log4j interfaces and classes that are addressable by {@linkplain org.apache.logging.log4j.plugins.Named name} or type
+ * including {@linkplain org.apache.logging.log4j.plugins.Configurable configurable plugins} which are created from a
+ * parsed tree of {@linkplain org.apache.logging.log4j.plugins.Node configuration nodes} along with other
+ * {@linkplain org.apache.logging.log4j.plugins.Namespace namespaces} for different dependency injection purposes.
  *
  * @see org.apache.logging.log4j.plugins.Inject
  * @see org.apache.logging.log4j.plugins.Plugin
  * @see org.apache.logging.log4j.plugins.PluginFactory
- * @see org.apache.logging.log4j.plugins.Namespace
+ * @see org.apache.logging.log4j.plugins.di.Injector
  */
 module org.apache.logging.log4j.plugins {
     exports org.apache.logging.log4j.plugins;
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
index aee5cf183c..cfb5d19964 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
@@ -67,7 +67,6 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.UnknownFormatConversionException;
 import java.util.concurrent.ConcurrentHashMap;
@@ -713,12 +712,12 @@ class DefaultInjector implements Injector {
 
     private Scope getScopeForMethod(final Method method) {
         final Annotation methodScope = AnnotationUtil.getMetaAnnotation(method, ScopeType.class);
-        return methodScope != null ? scopes.get(methodScope.annotationType()) : getScopeForType(method.getReturnType());
+        return methodScope != null ? getScope(methodScope.annotationType()) : getScopeForType(method.getReturnType());
     }
 
     private Scope getScopeForType(final Class<?> type) {
         final Annotation scope = AnnotationUtil.getMetaAnnotation(type, ScopeType.class);
-        return scope != null ? scopes.get(scope.annotationType()) : DefaultScope.INSTANCE;
+        return scope != null ? getScope(scope.annotationType()) : DefaultScope.INSTANCE;
     }
 
     private static boolean isCompatibleValidator(
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
index a35440b87d..c9b01a5aa2 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
@@ -17,6 +17,7 @@
 
 package org.apache.logging.log4j.plugins.di;
 
+import org.apache.logging.log4j.plugins.Configurable;
 import org.apache.logging.log4j.plugins.FactoryType;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.convert.TypeConverter;
@@ -26,16 +27,35 @@ import java.lang.reflect.Type;
 import java.util.function.Supplier;
 
 /**
- * Central interface for dependency injection operations. An Injector maintains a registry of bindings between {@link Key}s to
- * {@link Supplier}s along with a registry of {@link Scope}s for different scope annotation types. Injectors may be
- * {@linkplain #init() initialized} with {@link InjectorCallback} services.
+ * Manages dependency injection of a set of bindings between {@link Key}s and {@link Supplier}s lifecycle-bound to
+ * {@link Scope}s. Keys describe the type, name, namespace, qualifier type, and order of a binding. Suppliers are known
+ * as <i>factories</i>, and factories may have injectable dependencies on other bindings upon creation. Scopes control
+ * the lifecycle of instances returned by a binding's factory.
+ *
+ * <p>When first creating an Injector, invocation of {@link #init()} will invoke all registered {@link InjectorCallback}
+ * services in {@linkplain InjectorCallback#getOrder() numeric order}. These callbacks may register bindings
+ * {@linkplain #registerBinding(Key, Supplier) programmatically} or via {@linkplain #registerBundle(Object) bundle classes},
+ * and set a {@linkplain #setReflectionAccessor(ReflectionAccessor) default reflection accessor} for customizing the
+ * context in which private reflection operations are performed. Additional scopes
+ * {@linkplain #registerScope(Class, Scope) may also be registered}.</p>
+ *
+ * <p>Factories for keys can be looked up {@linkplain #getFactory(Key) by key} or {@linkplain #getFactory(Class) by class}.
+ * Any object created outside this system can have {@linkplain #injectMembers(Object) its members injected}.</p>
+ *
+ * <p>A parsed {@linkplain Node configuration node} can be {@linkplain #configure(Node) configured} using its referenced
+ * plugin class to return the plugin instance. Configuring a node configures its children nodes and consumes its
+ * attributes before returning the plugin instance.</p>
  */
 public interface Injector {
+    /**
+     * The key corresponding to the current Injector.
+     */
     Key<Injector> KEY = new Key<>() {};
 
     /**
      * Initializes this Injector with all registered {@link InjectorCallback} services in
-     * {@linkplain InjectorCallback#getOrder() integral order}.
+     * {@linkplain InjectorCallback#getOrder() integral order}. This method should only be invoked after construction
+     * of a fresh Injector.
      */
     void init();
 
@@ -107,7 +127,13 @@ public interface Injector {
     void injectMembers(final Object instance);
 
     /**
-     * Creates a plugin instance using the provided configuration node.
+     * Creates a plugin instance using the provided configuration node. Unless the plugin
+     * {@linkplain Configurable#deferChildren() defers children nodes}, child nodes are configured first before
+     * configuring this node. Each node's plugin should consume all supported
+     * {@linkplain org.apache.logging.log4j.plugins.PluginAttribute attributes} through dependency injection along with
+     * any other instances that can be provided through
+     * {@linkplain org.apache.logging.log4j.plugins.visit.NodeVisitor node visitor strategies} or general bindings from
+     * {@link #getFactory(Key)}. The end result of {@link Node#getObject()} is returned for convenience.
      *
      * @param node configuration node containing a plugin type, attributes, and child nodes to consume for dependency injection
      * @param <T>  type of instance the given node configures
@@ -133,7 +159,9 @@ public interface Injector {
 
     /**
      * Registers a bundle into this Injector. A bundle is an instance of a class with methods annotated with
-     * {@link FactoryType}-annotated annotations which provide dependency-injected bindings.
+     * {@link FactoryType}-annotated annotations which provide dependency-injected bindings. Bindings registered
+     * via bundles are merged with the existing bindings in this Injector based on the {@linkplain Key#getOrder() order}
+     * of the methods to determine ambiguities.
      *
      * @param bundle bundle to install with factory methods for factories
      */
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java
index b85658af16..4cd1156465 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java
@@ -86,25 +86,38 @@ public class Key<T> {
         hashCode = Objects.hash(type, qualifierType, name.toLowerCase(Locale.ROOT), namespace.toLowerCase(Locale.ROOT));
     }
 
+    /**
+     * Returns the generic type of this key.
+     */
     public final Type getType() {
         return type;
     }
 
+    /**
+     * Returns the raw type of this key corresponding to its generic type.
+     */
     public final Class<T> getRawType() {
         return rawType;
     }
 
+    /**
+     * Returns the name of this key. Names are case-insensitive. If this key has no defined name, then this returns
+     * an empty string.
+     */
     public final String getName() {
         return name;
     }
 
+    /**
+     * Returns the namespace of this key. If this key has no defined namespace, then this returns an empty string.
+     */
     public final String getNamespace() {
         return namespace;
     }
 
     /**
      * Returns the ordinal value of this key. Keys that are otherwise equal can be compared by this
-     * ordinal using the natural integer comparator.
+     * ordinal using the natural integer comparator where ties should default to keeping an existing binding intact.
      */
     public final int getOrder() {
         return order;