You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2017/05/21 08:28:04 UTC

logging-log4j2 git commit: LOG4J2-1917 - Use ServiceLoader to locate implementations.

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 671f30ba3 -> 92e4b8754


LOG4J2-1917 - Use ServiceLoader to locate implementations.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/92e4b875
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/92e4b875
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/92e4b875

Branch: refs/heads/master
Commit: 92e4b875463e8dc9e4683687d3572969f39b1593
Parents: 671f30b
Author: Ralph Goers <rg...@nextiva.com>
Authored: Sun May 21 01:27:57 2017 -0700
Committer: Ralph Goers <rg...@nextiva.com>
Committed: Sun May 21 01:27:57 2017 -0700

----------------------------------------------------------------------
 log4j-api/pom.xml                               | 23 ++++--
 .../org/apache/logging/log4j/spi/Provider.java  | 73 +++++++++++++++++---
 .../apache/logging/log4j/util/Activator.java    |  4 +-
 .../logging/log4j/util/ClassNamePredicate.java  | 45 ------------
 .../logging/log4j/util/ClassPredicate.java      | 46 ------------
 .../apache/logging/log4j/util/ProviderUtil.java | 11 +++
 .../log4j/util/StackWalkerStackLocator.java     | 63 -----------------
 .../logging/log4j/util/ClassNamePredicate.java  | 45 ++++++++++++
 .../logging/log4j/util/ClassPredicate.java      | 46 ++++++++++++
 .../log4j/util/StackWalkerStackLocator.java     | 63 +++++++++++++++++
 .../org/apache/logging/log4j/TestProvider.java  | 28 ++++++++
 .../META-INF/log4j-provider.properties          |  3 -
 .../org.apache.logging.log4j.spi.Provider       |  1 +
 .../logging/log4j/core/impl/Log4jProvider.java  | 28 ++++++++
 .../META-INF/log4j-provider.properties          | 18 -----
 .../org.apache.logging.log4j.spi.Provider       |  1 +
 .../appender/AsyncAppenderNoLocationTest.java   | 20 +++++-
 .../org/apache/logging/slf4j/SLF4JProvider.java | 28 ++++++++
 .../META-INF/log4j-provider.properties          | 19 -----
 .../org.apache.logging.log4j.spi.Provider       |  1 +
 src/changes/changes.xml                         |  3 +
 src/site/xdoc/manual/extending.xml              | 37 ++++++----
 22 files changed, 378 insertions(+), 228 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml
index bacf907..0b161d6 100644
--- a/log4j-api/pom.xml
+++ b/log4j-api/pom.xml
@@ -127,6 +127,23 @@
         </configuration>
       </plugin>
       <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>src/main/java9</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <executions>
@@ -134,12 +151,6 @@
             <id>default-compile</id>
             <!-- recompile everything for target VM except the module-info.java -->
             <configuration>
-              <excludes>
-                <exclude>module-info.java</exclude>
-                <exclude>**/util/ClassNamePredicate.java</exclude>
-                <exclude>**/util/ClassPredicate.java</exclude>
-                <exclude>**/util/StackWalkerStackLocator.java</exclude>
-              </excludes>
               <source>1.7</source>
               <target>1.7</target>
             </configuration>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
index 7ed3af5..a50c227 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
@@ -47,7 +47,10 @@ public class Provider {
 
     private final Integer priority;
     private final String className;
+    private final Class<? extends LoggerContextFactory> loggerContextFactoryClass;
     private final String threadContextMap;
+    private final Class<? extends ThreadContextMap> threadContextMapClass;
+    private final String versions;
     private final URL url;
     private final WeakReference<ClassLoader> classLoader;
 
@@ -58,6 +61,36 @@ public class Provider {
         priority = weight == null ? DEFAULT_PRIORITY : Integer.valueOf(weight);
         className = props.getProperty(LOGGER_CONTEXT_FACTORY);
         threadContextMap = props.getProperty(THREAD_CONTEXT_MAP);
+        loggerContextFactoryClass = null;
+        threadContextMapClass = null;
+        versions = null;
+    }
+
+    public Provider(Integer priority, String versions,
+                    Class<? extends LoggerContextFactory> loggerContextFactoryClass) {
+        this(priority, versions, loggerContextFactoryClass, null);
+    }
+
+
+    public Provider(Integer priority, String versions,
+                    Class<? extends LoggerContextFactory> loggerContextFactoryClass,
+                    Class<? extends ThreadContextMap> threadContextMapClass) {
+        this.url = null;
+        this.classLoader = null;
+        this.priority = priority;
+        this.loggerContextFactoryClass = loggerContextFactoryClass;
+        this.threadContextMapClass = threadContextMapClass;
+        this.className = null;
+        this.threadContextMap = null;
+        this.versions = versions;
+    }
+
+    /**
+     * Returns the Log4j API versions supported by the implementation.
+     * @return A String containing the Log4j versions supported.
+     */
+    public String getVersions() {
+        return versions;
     }
 
     /**
@@ -76,6 +109,9 @@ public class Provider {
      * @return the class name of a LoggerContextFactory implementation
      */
     public String getClassName() {
+        if (loggerContextFactoryClass != null) {
+            return loggerContextFactoryClass.getName();
+        }
         return className;
     }
 
@@ -85,6 +121,9 @@ public class Provider {
      * @return the LoggerContextFactory implementation class or {@code null} if there was an error loading it
      */
     public Class<? extends LoggerContextFactory> loadLoggerContextFactory() {
+        if (loggerContextFactoryClass != null) {
+            return loggerContextFactoryClass;
+        }
         if (className == null) {
             return null;
         }
@@ -109,6 +148,9 @@ public class Provider {
      * @return the class name of a ThreadContextMap implementation
      */
     public String getThreadContextMap() {
+        if (threadContextMapClass != null) {
+            return threadContextMapClass.getName();
+        }
         return threadContextMap;
     }
 
@@ -118,6 +160,9 @@ public class Provider {
      * @return the ThreadContextMap implementation class or {@code null} if there was an error loading it
      */
     public Class<? extends ThreadContextMap> loadThreadContextMap() {
+        if (threadContextMapClass != null) {
+            return threadContextMapClass;
+        }
         if (threadContextMap == null) {
             return null;
         }
@@ -147,24 +192,30 @@ public class Provider {
     
     @Override
     public String toString() {
-        String result = "Provider[";
+        StringBuilder result = new StringBuilder("Provider[");
         if (!DEFAULT_PRIORITY.equals(priority)) {
-            result += "priority=" + priority + ", ";
+            result.append("priority=").append(priority).append(", ");
         }
         if (threadContextMap != null) {
-            result += "threadContextMap=" + threadContextMap + ", ";
+            result.append("threadContextMap=").append(threadContextMap).append(", ");
+        } else if (threadContextMapClass != null) {
+            result.append("threadContextMapClass=").append(threadContextMapClass.getName());
         }
         if (className != null) {
-            result += "className=" + className + ", ";
+            result.append("className=").append(className).append(", ");
+        } else if (loggerContextFactoryClass != null) {
+            result.append("class=").append(loggerContextFactoryClass.getName());
         }
-        result += "url=" + url;
-        final ClassLoader loader = classLoader.get();
-        if (loader == null) {
-            result += ", classLoader=null(not reachable)";
+        if (url != null) {
+            result.append("url=").append(url);
+        }
+        final ClassLoader loader;
+        if (classLoader == null || (loader = classLoader.get()) == null) {
+            result.append(", classLoader=null(not reachable)");
         } else {
-            result += ", classLoader=" + loader;
+            result.append(", classLoader=").append(loader);
         }
-        result += "]";
-        return result;
+        result.append("]");
+        return result.toString();
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java
index bcf3bc4..f35ace8 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.util;
 
+import javax.annotation.processing.ProcessingEnvironment;
 import java.net.URL;
 import java.security.Permission;
 import java.util.List;
@@ -72,6 +73,7 @@ public class Activator implements BundleActivator, SynchronousBundleListener {
     }
 
     private void loadProvider(final BundleWiring provider) {
+        ProviderUtil.loadProviders(provider.getClassLoader());
         final List<URL> urls = provider.findEntries("META-INF", "log4j-provider.properties", 0);
         for (final URL url : urls) {
             ProviderUtil.loadProvider(url, provider.getClassLoader());
@@ -83,7 +85,7 @@ public class Activator implements BundleActivator, SynchronousBundleListener {
         ProviderUtil.STARTUP_LOCK.lock();
         lockingProviderUtil = true;
         final BundleWiring self = context.getBundle().adapt(BundleWiring.class);
-        final List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName());
+        List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName());
         for (final BundleWire wire : required) {
             loadProvider(wire.getProviderWiring());
         }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java
deleted file mode 100644
index 063e538..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.util;
-
-import java.util.function.Predicate;
-
-/**
- * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class.
- */
-public final class ClassNamePredicate implements Predicate<StackWalker.StackFrame> {
-
-    private final String fqcn;
-
-    public ClassNamePredicate(String fqcn) {
-        this.fqcn = fqcn;
-    }
-
-    private boolean next = false;
-
-    @Override
-    public boolean test(StackWalker.StackFrame f) {
-        if (fqcn.equals(f.getClassName())) {
-            next = true;
-            return false;
-        } else if (next) {
-            next = false;
-            return true;
-        }
-        return false;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java
deleted file mode 100644
index 3f8d15a..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.util;
-
-import java.util.function.Predicate;
-
-/**
- * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class.
- */
-
-public final class ClassPredicate implements Predicate<StackWalker.StackFrame> {
-
-    private final Class<?> clazz;
-
-    public ClassPredicate(Class<?> clazz) {
-        this.clazz = clazz;
-    }
-
-    private boolean next = false;
-
-    @Override
-    public boolean test(StackWalker.StackFrame f) {
-        if (clazz.equals(f.getDeclaringClass())) {
-            next = true;
-            return false;
-        } else if (next) {
-            next = false;
-            return true;
-        }
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
index 498bda9..b5be525 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Properties;
+import java.util.ServiceLoader;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -62,6 +63,7 @@ public final class ProviderUtil {
     private static volatile ProviderUtil instance;
 
     private ProviderUtil() {
+        loadProviders(findClassLoader());
         for (final LoaderUtil.UrlResource resource : LoaderUtil.findUrlResources(PROVIDER_RESOURCE)) {
             loadProvider(resource.getUrl(), resource.getClassLoader());
         }
@@ -87,6 +89,15 @@ public final class ProviderUtil {
         }
     }
 
+    protected static void loadProviders(final ClassLoader cl) {
+        ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, cl);
+        for (Provider provider : serviceLoader) {
+            if (validVersion(provider.getVersions())) {
+                PROVIDERS.add(provider);
+            }
+        }
+    }
+
     /**
      * @deprecated Use {@link #loadProvider(java.net.URL, ClassLoader)} instead. Will be removed in 3.0.
      */

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java
deleted file mode 100644
index dc10fef..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.util;
-
-import java.util.List;
-import java.util.Stack;
-import java.util.stream.Collectors;
-
-/**
- * <em>Consider this class private.</em> Determines the caller's class.
- */
-public class StackWalkerStackLocator implements StackLocator {
-
-    private final static StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
-
-    private final static StackWalker stackWalker = StackWalker.getInstance();
-
-    public Class<?> getCallerClass(final String fqcn) {
-        return getCallerClass(fqcn, "");
-    }
-
-    public Class<?> getCallerClass(final String fqcn, final String pkg) {
-        return walker.walk(s -> s.filter(new ClassNamePredicate(fqcn)).findFirst()).get().getDeclaringClass();
-    }
-
-    public Class<?> getCallerClass(final Class<?> anchor) {
-        return walker.walk(s -> s.filter(new ClassPredicate(anchor)).findFirst()).get().getDeclaringClass();
-    }
-
-    public Class<?> getCallerClass(final int depth) {
-        ;
-        return walker.walk(s -> s.skip(depth).findFirst()).get().getDeclaringClass();
-    }
-
-    public Stack<Class<?>> getCurrentStackTrace() {
-        Stack<Class<?>> stack = new Stack<Class<?>>();
-        List<Class<?>> classes = walker.walk(s -> s.map(f -> f.getDeclaringClass()).collect(Collectors.toList()));
-        stack.addAll(classes);
-        return stack;
-    }
-
-    public StackTraceElement calcLocation(final String fqcnOfLogger) {
-        return stackWalker.walk(s -> s.filter(new ClassNamePredicate(fqcnOfLogger)).findFirst()).get().toStackTraceElement();
-    }
-
-    public StackTraceElement getStackTraceElement(final int depth) {
-        return stackWalker.walk(s -> s.skip(depth).findFirst()).get().toStackTraceElement();
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java
new file mode 100644
index 0000000..063e538
--- /dev/null
+++ b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.util;
+
+import java.util.function.Predicate;
+
+/**
+ * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class.
+ */
+public final class ClassNamePredicate implements Predicate<StackWalker.StackFrame> {
+
+    private final String fqcn;
+
+    public ClassNamePredicate(String fqcn) {
+        this.fqcn = fqcn;
+    }
+
+    private boolean next = false;
+
+    @Override
+    public boolean test(StackWalker.StackFrame f) {
+        if (fqcn.equals(f.getClassName())) {
+            next = true;
+            return false;
+        } else if (next) {
+            next = false;
+            return true;
+        }
+        return false;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java
new file mode 100644
index 0000000..3f8d15a
--- /dev/null
+++ b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.util;
+
+import java.util.function.Predicate;
+
+/**
+ * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class.
+ */
+
+public final class ClassPredicate implements Predicate<StackWalker.StackFrame> {
+
+    private final Class<?> clazz;
+
+    public ClassPredicate(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    private boolean next = false;
+
+    @Override
+    public boolean test(StackWalker.StackFrame f) {
+        if (clazz.equals(f.getDeclaringClass())) {
+            next = true;
+            return false;
+        } else if (next) {
+            next = false;
+            return true;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java b/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java
new file mode 100644
index 0000000..dc10fef
--- /dev/null
+++ b/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.util;
+
+import java.util.List;
+import java.util.Stack;
+import java.util.stream.Collectors;
+
+/**
+ * <em>Consider this class private.</em> Determines the caller's class.
+ */
+public class StackWalkerStackLocator implements StackLocator {
+
+    private final static StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+
+    private final static StackWalker stackWalker = StackWalker.getInstance();
+
+    public Class<?> getCallerClass(final String fqcn) {
+        return getCallerClass(fqcn, "");
+    }
+
+    public Class<?> getCallerClass(final String fqcn, final String pkg) {
+        return walker.walk(s -> s.filter(new ClassNamePredicate(fqcn)).findFirst()).get().getDeclaringClass();
+    }
+
+    public Class<?> getCallerClass(final Class<?> anchor) {
+        return walker.walk(s -> s.filter(new ClassPredicate(anchor)).findFirst()).get().getDeclaringClass();
+    }
+
+    public Class<?> getCallerClass(final int depth) {
+        ;
+        return walker.walk(s -> s.skip(depth).findFirst()).get().getDeclaringClass();
+    }
+
+    public Stack<Class<?>> getCurrentStackTrace() {
+        Stack<Class<?>> stack = new Stack<Class<?>>();
+        List<Class<?>> classes = walker.walk(s -> s.map(f -> f.getDeclaringClass()).collect(Collectors.toList()));
+        stack.addAll(classes);
+        return stack;
+    }
+
+    public StackTraceElement calcLocation(final String fqcnOfLogger) {
+        return stackWalker.walk(s -> s.filter(new ClassNamePredicate(fqcnOfLogger)).findFirst()).get().toStackTraceElement();
+    }
+
+    public StackTraceElement getStackTraceElement(final int depth) {
+        return stackWalker.walk(s -> s.skip(depth).findFirst()).get().toStackTraceElement();
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java b/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java
new file mode 100644
index 0000000..f96181a
--- /dev/null
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j;
+
+import org.apache.logging.log4j.spi.Provider;
+
+/**
+ * Binding for the Log4j API.
+ */
+public class TestProvider extends Provider {
+    public TestProvider() {
+        super(0, "2.6.0", TestLoggerContextFactory.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/test/resources/META-INF/log4j-provider.properties
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/resources/META-INF/log4j-provider.properties b/log4j-api/src/test/resources/META-INF/log4j-provider.properties
deleted file mode 100644
index 36fc6d6..0000000
--- a/log4j-api/src/test/resources/META-INF/log4j-provider.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-LoggerContextFactory = org.apache.logging.log4j.TestLoggerContextFactory
-Log4jAPIVersion = 2.6.0
-FactoryPriority = 0
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider b/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
new file mode 100644
index 0000000..5ae649a
--- /dev/null
+++ b/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
@@ -0,0 +1 @@
+org.apache.logging.log4j.TestProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java
new file mode 100644
index 0000000..499fb45
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.impl;
+
+import org.apache.logging.log4j.spi.Provider;
+
+/**
+ * Binding for the Log4j API.
+ */
+public class Log4jProvider extends Provider {
+    public Log4jProvider() {
+        super(10, "2.6.0", Log4jContextFactory.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/main/resources/META-INF/log4j-provider.properties
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/resources/META-INF/log4j-provider.properties b/log4j-core/src/main/resources/META-INF/log4j-provider.properties
deleted file mode 100644
index 2335e85..0000000
--- a/log4j-core/src/main/resources/META-INF/log4j-provider.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LoggerContextFactory = org.apache.logging.log4j.core.impl.Log4jContextFactory
-Log4jAPIVersion = 2.6.0
-FactoryPriority= 10

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider b/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
new file mode 100644
index 0000000..c4c6c6c
--- /dev/null
+++ b/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
@@ -0,0 +1 @@
+org.apache.logging.log4j.core.impl.Log4jProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java
index ba7da83..17865a8 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java
@@ -36,11 +36,26 @@ public class AsyncAppenderNoLocationTest {
     private ListAppender app;
 
     @ClassRule
-    public static LoggerContextRule init = new LoggerContextRule("log4j-asynch-no-location.xml");
+    public static LoggerContextRule init = null;
+
+            static {
+                try {
+                    init = new LoggerContextRule("log4j-asynch-no-location.xml");
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            }
 
     @Before
     public void setUp() throws Exception {
-        this.app = (ListAppender) init.getAppender("List");
+                try {
+                    this.app = (ListAppender) init.getAppender("List");
+                    assertNotNull("No List appender found", app);
+                } catch (Exception ex) {
+                    System.out.println("init = " + init == null ? "null" : init);
+
+                }
+
     }
 
     @After
@@ -56,6 +71,7 @@ public class AsyncAppenderNoLocationTest {
         logger.error("This is a test");
         logger.warn("Hello world!");
         Thread.sleep(100);
+        System.out.println("app = " + app == null ? "null" : app);
         final List<String> list = app.getMessages();
         assertNotNull("No events generated", list);
         assertEquals("Incorrect number of events. Expected 2, got " + list.size(), list.size(), 2);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java
----------------------------------------------------------------------
diff --git a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java
new file mode 100644
index 0000000..979d5e9
--- /dev/null
+++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.slf4j;
+
+import org.apache.logging.log4j.spi.Provider;
+
+/**
+ * Bind the Log4j API to SLF4J.
+ */
+public class SLF4JProvider extends Provider {
+    public SLF4JProvider() {
+        super(15, "2.6.0", SLF4JLoggerContextFactory.class, MDCContextMap.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties
----------------------------------------------------------------------
diff --git a/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties b/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties
deleted file mode 100644
index f213cc2..0000000
--- a/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LoggerContextFactory = org.apache.logging.slf4j.SLF4JLoggerContextFactory
-Log4jAPIVersion = 2.6.0
-FactoryPriority= 15
-ThreadContextMap = org.apache.logging.slf4j.MDCContextMap
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
----------------------------------------------------------------------
diff --git a/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider b/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
new file mode 100644
index 0000000..c66b5c9
--- /dev/null
+++ b/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider
@@ -0,0 +1 @@
+org.apache.logging.slf4j.SLF4JProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 9681eb4..db263d1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -31,6 +31,9 @@
          - "remove" - Removed
     -->
     <release version="2.9.0" date="2017-MM-DD" description="GA Release 2.9.0">
+      <action issue="LOG4J2-1917" dev="rgoers" type="update">
+        Support using java.util.ServiceLoader to locate Log4j 2 API providers.
+      </action>
       <action issue="LOG4J2-1854" dev="mikes" type="add" due-to="Xavier Jodoin">
         Support null byte delimiter in GelfLayout.
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/src/site/xdoc/manual/extending.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/extending.xml b/src/site/xdoc/manual/extending.xml
index 357bb67..4362cfb 100644
--- a/src/site/xdoc/manual/extending.xml
+++ b/src/site/xdoc/manual/extending.xml
@@ -33,25 +33,34 @@
           <subsection name="LoggerContextFactory">
             <p>
               The <code>LoggerContextFactory</code> binds the Log4j API to its implementation. The Log4j
-              <code>LogManager</code> locates a <code>LoggerContextFactory</code> by locating all instances of
-              <code>META-INF/log4j-provider.properties</code>, a standard <code>java.util.Properties</code> file,
-              and then inspecting each to verify that it specifies a value for the <var>Log4jAPIVersion</var> property
-              that conforms to the version required by the <code>LogManager</code>. If more than one valid
-              implementation is located the value for <var>FactoryPriority</var> will be used to identify the factory
-              with the highest priority. Finally, the value of the <var>LoggerContextFactory</var> property will be
-              used to locate the <code>LoggerContextFactory</code>. In Log4j 2 this is provided by
-              <code>Log4jContextFactory</code>.
+              <code>LogManager</code> locates a <code>LoggerContextFactory</code> by using java.util.ServiceLoader
+              to locate all instances of <code>org.apache.logging.log4j.spi.Provider</code>. Each implementation must
+              provide a class that extends<code>org.apache.logging.log4j.spi.Provider</code> and should have a
+              no-arg constructor that delegates to Provider's constructor passing the <var>Priority</var>,
+              the API versions it is compatible with, and the class that implements
+              <code>org.apache.logging.log4j.spi.LoggerContextFactory</code>. Log4j will compare the current API
+              version and if it is compatible the implementation will be added to the list of providers. The
+              API version in <code>org.apache.logging.log4j.LogManager</code> is only changed when a feature is added
+              to the API that implementations need to be aware of. If more than one valid implementation is located
+              the value for the <var>Priority</var> will be used to identify the factory with the highest priority.
+              Finally, the class that implements <code>org.apache.logging.log4j.spi.LoggerContextFactory</code> will be
+              instantiated and bound to the LogManager. In Log4j 2 this is provided by <code>Log4jContextFactory</code>.
             </p>
             <p>
               Applications may change the LoggerContextFactory that will be used by
             </p>
             <ol>
-              <li>Implementing a new <code>LoggerContextFactory</code> and creating a <code>log4j-provider.properties</code>
-                to reference it making sure that it has the highest priority.
-              </li>
-              <li>Create a new <code>log4j-provider.xml</code> and configure it with the desired
-                <code>LoggerContextFactory</code> making sure that it has the highest priority.
-              </li>
+              <li>Create a binding to the logging implementation.
+              <ol style="list-style-type: lower-alpha">
+                <li>Implement a new <code>LoggerContextFactory</code>.</li>
+                <li>Implement a class that extends <code>org.apache.logging.spi.Provider.</code> with a no-arg
+                  constructor that calls super-class's constructor with the <var>Priority</var>, the API version(s),
+                  <code>LoggerContextFactory</code> class, and optinall, a <code>ThreadContextMap</code>
+                  implementation class.</li>
+                <li>Create a <code>META-INF/services/org.apache.logging.spi.Provider</code> file that contains the
+                  name of the class that implements <code>org.apache.logging.spi.Provider</code>.
+                </li>
+              </ol></li>
               <li>Setting the system property <var>log4j2.loggerContextFactory</var> to the name of the
                 <code>LoggerContextFactory</code> class to use.
               </li>