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 2023/11/14 06:19:10 UTC

(logging-log4j2) 07/07: Remove ServiceRegistry in favor of utility function

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

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

commit 3118f4799728d6b2b987a1858ac80b4c8579fc38
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Tue Nov 14 00:06:39 2023 -0600

    Remove ServiceRegistry in favor of utility function
    
    Without a need for tracking externally registered services, everywhere that was looking up services can do so more directly now.
    
    Signed-off-by: Matt Sicker <ma...@apache.org>
---
 .../logging/log4j/util/ServiceLoaderUtilTest.java  |  27 ++--
 .../logging/log4j/message/ThreadDumpMessage.java   |  16 +--
 .../apache/logging/log4j/spi/LoggingSystem.java    |   9 +-
 .../apache/logging/log4j/util/PropertiesUtil.java  |  41 ++----
 .../logging/log4j/util/ServiceLoaderUtil.java      | 142 +++------------------
 .../apache/logging/log4j/util/ServiceRegistry.java |  81 ------------
 .../log4j/core/config/AbstractConfiguration.java   |  11 +-
 .../log4j/core/impl/ThreadContextDataInjector.java |  22 ++--
 .../logging/log4j/core/util/WatchManager.java      |  12 +-
 .../org/apache/logging/log4j/plugins/di/DI.java    |   8 +-
 10 files changed, 76 insertions(+), 293 deletions(-)

diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
index e6d9d704bd..b82fb953b2 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 import java.util.stream.Collectors;
 
 import org.apache.logging.log4j.Level;
@@ -32,29 +32,30 @@ import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class ServiceLoaderUtilTest {
 
     @Test
     public void testServiceResolution() {
-            final List<Object> services = new ArrayList<>();
-            assertDoesNotThrow(() -> ServiceLoaderUtil.loadServices(BetterService.class, MethodHandles.lookup(), false)
-                    .forEach(services::add));
-            assertThat(services).hasSize(1);
-            services.clear();
-            assertDoesNotThrow(() -> ServiceLoaderUtil.loadServices(PropertySource.class, MethodHandles.lookup(), false)
-                    .forEach(services::add));
-            assertThat(services).hasSize(3);
-        }
+        final List<Object> services = new ArrayList<>();
+        final ClassLoader classLoader = getClass().getClassLoader();
+        assertDoesNotThrow(() -> ServiceLoaderUtil.safeStream(ServiceLoader.load(BetterService.class, classLoader))
+                .forEach(services::add));
+        assertThat(services).hasSize(1);
+        services.clear();
+        assertDoesNotThrow(() -> ServiceLoaderUtil.safeStream(ServiceLoader.load(PropertySource.class, classLoader))
+                .forEach(services::add));
+        assertThat(services).hasSize(3);
+    }
 
     @Test
     @UsingStatusListener
     public void testBrokenServiceFile(final ListStatusListener listener) {
         final List<Service> services = new ArrayList<>();
-        assertDoesNotThrow(() -> ServiceLoaderUtil.loadServices(Service.class, MethodHandles.lookup(), false)
+        final ClassLoader classLoader = getClass().getClassLoader();
+        assertDoesNotThrow(() -> ServiceLoaderUtil.safeStream(ServiceLoader.load(Service.class, classLoader))
                 .forEach(services::add));
-        assertEquals(2, services.size());
+        assertThat(services).hasSize(2);
         // A warning for each broken service
         final List<Throwable> errors = listener.findStatusData(Level.WARN).map(StatusData::getThrowable)
                 .collect(Collectors.toList());
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
index cbfa241b5b..585728251f 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
@@ -16,16 +16,15 @@
  */
 package org.apache.logging.log4j.message;
 
-import java.lang.invoke.MethodHandles;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.ServiceLoader;
 
 import aQute.bnd.annotation.Cardinality;
-import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import org.apache.logging.log4j.message.ThreadDumpMessage.ThreadInfoFactory;
 import org.apache.logging.log4j.util.Lazy;
-import org.apache.logging.log4j.util.ServiceRegistry;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
 import org.apache.logging.log4j.util.StringBuilderFormattable;
 import org.apache.logging.log4j.util.Strings;
 
@@ -33,13 +32,12 @@ import org.apache.logging.log4j.util.Strings;
  * Captures information about all running Threads.
  */
 @AsynchronouslyFormattable
-@ServiceConsumer(value = ThreadInfoFactory.class, resolution = Resolution.OPTIONAL, cardinality = Cardinality.SINGLE)
+@ServiceConsumer(value = ThreadInfoFactory.class, cardinality = Cardinality.SINGLE)
 public class ThreadDumpMessage implements Message, StringBuilderFormattable {
-    private static final Lazy<ThreadInfoFactory> FACTORY = Lazy.lazy(() -> {
-        final var services = ServiceRegistry.getInstance()
-                .getServices(ThreadInfoFactory.class, MethodHandles.lookup(), null);
-        return services.isEmpty() ? new BasicThreadInfoFactory() : services.get(0);
-    });
+    private static final Lazy<ThreadInfoFactory> FACTORY = Lazy.lazy(() ->
+            ServiceLoaderUtil.safeStream(ServiceLoader.load(ThreadInfoFactory.class, ThreadInfoFactory.class.getClassLoader()))
+                    .findFirst()
+                    .orElseGet(BasicThreadInfoFactory::new));
 
     private final Map<ThreadInformation, StackTraceElement[]> threads;
     private final String title;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
index 4691a74c48..55dbf3ecc3 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
@@ -18,13 +18,13 @@ package org.apache.logging.log4j.spi;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.util.List;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.ServiceLoader;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.function.Supplier;
@@ -45,7 +45,7 @@ import org.apache.logging.log4j.util.LoaderUtil;
 import org.apache.logging.log4j.util.LowLevelLogUtil;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.PropertyEnvironment;
-import org.apache.logging.log4j.util.ServiceRegistry;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
 
 import static org.apache.logging.log4j.spi.LoggingSystemProperty.LOGGER_FLOW_MESSAGE_FACTORY_CLASS;
 import static org.apache.logging.log4j.spi.LoggingSystemProperty.LOGGER_MESSAGE_FACTORY_CLASS;
@@ -187,8 +187,9 @@ public class LoggingSystem {
     }
 
     private static List<Provider> loadDefaultProviders() {
-        return ServiceRegistry.getInstance()
-                .getServices(Provider.class, MethodHandles.lookup(), provider -> validVersion(provider.getVersions()));
+        return ServiceLoaderUtil.safeStream(ServiceLoader.load(Provider.class, Provider.class.getClassLoader()))
+                .filter(provider -> validVersion(provider.getVersions()))
+                .collect(Collectors.toList());
     }
 
     private static List<Provider> loadLegacyProviders() {
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index d656f89b5d..86a7a34c7c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -20,7 +20,6 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.invoke.MethodHandles;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -38,9 +37,9 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
 
 import aQute.bnd.annotation.Cardinality;
-import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import org.apache.logging.log4j.internal.CopyOnWriteNavigableSet;
 
@@ -58,7 +57,7 @@ import org.apache.logging.log4j.internal.CopyOnWriteNavigableSet;
  * @see PropertySource
  */
 @InternalApi
-@ServiceConsumer(value = PropertySource.class, resolution = Resolution.OPTIONAL, cardinality = Cardinality.MULTIPLE)
+@ServiceConsumer(value = PropertySource.class, cardinality = Cardinality.MULTIPLE)
 public class PropertiesUtil implements PropertyEnvironment {
 
     private static final String LOG4J_NAMESPACE = "component";
@@ -66,6 +65,9 @@ public class PropertiesUtil implements PropertyEnvironment {
     private static final String DELIMITER = ".";
     private static final String META_INF = "META-INF/";
     private static final String LOG4J_SYSTEM_PROPERTIES_FILE_NAME = "log4j2.system.properties";
+    private static final Lazy<List<PropertySource>> SERVICE_PROPERTY_SOURCES = Lazy.lazy(() ->
+            ServiceLoaderUtil.safeStream(ServiceLoader.load(PropertySource.class, PropertiesUtil.class.getClassLoader()))
+                    .collect(Collectors.toList()));
     private static final Lazy<PropertiesUtil> COMPONENT_PROPERTIES = Lazy.lazy(PropertiesUtil::new);
 
     private static final ThreadLocal<PropertiesUtil> environments = new InheritableThreadLocal<>();
@@ -234,21 +236,6 @@ public class PropertiesUtil implements PropertyEnvironment {
         return environment.getStringProperty(name);
     }
 
-    /**
-     * Return the system properties or an empty Properties object if an error occurs.
-     *
-     * @return The system properties.
-     */
-    public static Properties getSystemProperties() {
-        try {
-            return new Properties(System.getProperties());
-        } catch (final SecurityException ex) {
-            LowLevelLogUtil.logException("Unable to access system properties.", ex);
-            // Sandboxed - can't read System Properties
-            return new Properties();
-        }
-    }
-
     /**
      * Reloads all properties. This is primarily useful for unit tests.
      *
@@ -438,20 +425,14 @@ public class PropertiesUtil implements PropertyEnvironment {
         private final String contextName;
 
         private Environment(final String contextName, final List<PropertySource> propertySources) {
-            try {
-                final Properties sysProps = PropertyFilePropertySource.loadPropertiesFile(LOG4J_SYSTEM_PROPERTIES_FILE_NAME);
-                for (String key : sysProps.stringPropertyNames()) {
-                    if (System.getProperty(key) == null) {
-                        System.setProperty(key, sysProps.getProperty(key));
-                    }
-                };
-            } catch (final SecurityException ex) {
-                // Access to System Properties is restricted so just skip it.
+            final Properties sysProps = PropertyFilePropertySource.loadPropertiesFile(LOG4J_SYSTEM_PROPERTIES_FILE_NAME);
+            for (String key : sysProps.stringPropertyNames()) {
+                if (System.getProperty(key) == null) {
+                    System.setProperty(key, sysProps.getProperty(key));
+                }
             }
             sources.addAll(propertySources);
-            final ServiceRegistry registry = ServiceRegistry.getInstance();
-            // Does not log errors using StatusLogger, which depends on PropertiesUtil being initialized.
-            sources.addAll(registry.getServices(PropertySource.class, MethodHandles.lookup(), null, /*verbose=*/false));
+            sources.addAll(SERVICE_PROPERTY_SOURCES.get());
             this.contextName = contextName;
             reload();
         }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
index 95c9f3cef8..084555f36d 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
@@ -16,29 +16,18 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.lang.invoke.CallSite;
-import java.lang.invoke.LambdaMetafactory;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import java.util.Set;
-import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
-
 /**
- * This class should be considered internal.
+ * Handles {@link ServiceLoader} lookups with better error handling.
  */
 @InternalApi
 public final class ServiceLoaderUtil {
@@ -48,102 +37,21 @@ public final class ServiceLoaderUtil {
     private ServiceLoaderUtil() {
     }
 
-    /**
-     * Retrieves the available services from the caller's classloader.
-     *
-     * Broken services will be ignored.
-     *
-     * @param <T>         The service type.
-     * @param serviceType The class of the service.
-     * @param lookup      The calling class data.
-     * @return A stream of service instances.
-     */
-    public static <T> Stream<T> loadServices(final Class<T> serviceType, final Lookup lookup) {
-        return loadServices(serviceType, lookup, false);
-    }
-
-    /**
-     * Retrieves the available services from the caller's classloader and possibly
-     * the thread context classloader.
-     *
-     * Broken services will be ignored.
-     *
-     * @param <T>         The service type.
-     * @param serviceType The class of the service.
-     * @param lookup      The calling class data.
-     * @param useTccl     If true the thread context classloader will also be used.
-     * @return A stream of service instances.
-     */
-    public static <T> Stream<T> loadServices(final Class<T> serviceType, final Lookup lookup, final boolean useTccl) {
-        return loadServices(serviceType, lookup, useTccl, true);
-    }
-
-    static <T> Stream<T> loadServices(final Class<T> serviceType, final Lookup lookup, final boolean useTccl,
-            final boolean verbose) {
-        final ClassLoader classLoader = lookup.lookupClass().getClassLoader();
-        Stream<T> services = loadClassloaderServices(serviceType, lookup, classLoader, verbose);
-        if (useTccl) {
-            final ClassLoader contextClassLoader = LoaderUtil.getThreadContextClassLoader();
-            if (contextClassLoader != classLoader) {
-                services = Stream.concat(services,
-                        loadClassloaderServices(serviceType, lookup, contextClassLoader, verbose));
-            }
-        }
+    public static <S> Stream<S> safeStream(final ServiceLoader<S> serviceLoader) {
         final Set<Class<?>> classes = new HashSet<>();
-        // only the first occurrence of a class
-        return services.filter(service -> classes.add(service.getClass()));
-    }
-
-    static <T> Stream<T> loadClassloaderServices(final Class<T> serviceType, final Lookup lookup,
-            final ClassLoader classLoader, final boolean verbose) {
-        return StreamSupport.stream(new ServiceLoaderSpliterator<T>(serviceType, lookup, classLoader, verbose), false);
-    }
-
-    static <T> Iterable<T> callServiceLoader(final Lookup lookup, final Class<T> serviceType, final ClassLoader classLoader,
-            final boolean verbose) {
-        try {
-            // Creates a lambda in the caller's domain that calls `ServiceLoader`
-            final MethodHandle loadHandle = lookup.findStatic(ServiceLoader.class, "load",
-                    MethodType.methodType(ServiceLoader.class, Class.class, ClassLoader.class));
-            final CallSite callSite = LambdaMetafactory.metafactory(lookup,
-                    "run",
-                    MethodType.methodType(PrivilegedAction.class, Class.class, ClassLoader.class),
-                    MethodType.methodType(Object.class),
-                    loadHandle,
-                    MethodType.methodType(ServiceLoader.class));
-            final PrivilegedAction<ServiceLoader<T>> action = (PrivilegedAction<ServiceLoader<T>>) callSite
-                    .getTarget()//
-                    .bindTo(serviceType)
-                    .bindTo(classLoader)
-                    .invoke();
-            final ServiceLoader<T> serviceLoader;
-            if (System.getSecurityManager() == null) {
-                serviceLoader = action.run();
-            } else {
-                final MethodHandle privilegedHandle = lookup.findStatic(AccessController.class, "doPrivileged",
-                        MethodType.methodType(Object.class, PrivilegedAction.class));
-                serviceLoader = (ServiceLoader<T>) privilegedHandle.invoke(action);
-            }
-            return serviceLoader;
-        } catch (Throwable e) {
-            if (verbose) {
-                StatusLogger.getLogger().error("Unable to load services for service {}", serviceType, e);
-            }
-        }
-        return Collections.emptyList();
+        return StreamSupport.stream(new ServiceLoaderSpliterator<>(serviceLoader), false)
+                // only the first occurrence of a class
+                .filter(service -> classes.add(service.getClass()));
     }
 
-    private static class ServiceLoaderSpliterator<S> implements Spliterator<S> {
-
+    private static class ServiceLoaderSpliterator<S> extends Spliterators.AbstractSpliterator<S> {
         private final Iterator<S> serviceIterator;
-        private final Logger logger;
         private final String serviceName;
 
-        public ServiceLoaderSpliterator(final Class<S> serviceType, final Lookup lookup, final ClassLoader classLoader,
-                final boolean verbose) {
-            this.serviceIterator = callServiceLoader(lookup, serviceType, classLoader, verbose).iterator();
-            this.logger = verbose ? StatusLogger.getLogger() : null;
-            this.serviceName = serviceType.toString();
+        private ServiceLoaderSpliterator(final ServiceLoader<S> serviceLoader) {
+            super(Long.MAX_VALUE, ORDERED);
+            serviceIterator = serviceLoader.iterator();
+            serviceName = serviceLoader.toString();
         }
 
         @Override
@@ -155,34 +63,14 @@ public final class ServiceLoaderUtil {
                         action.accept(serviceIterator.next());
                         return true;
                     }
-                } catch (ServiceConfigurationError | LinkageError e) {
-                    if (logger != null) {
-                        logger.warn("Unable to load service class for service {}", serviceName, e);
-                    }
-                } catch (Throwable e) {
-                    if (logger != null) {
-                        logger.warn("Unable to load service class for service {}", serviceName, e);
-                    }
+                } catch (final ServiceConfigurationError | LinkageError e) {
+                    LowLevelLogUtil.logException("Unable to load implementation for " + serviceName, e);
+                } catch (final Throwable e) {
+                    LowLevelLogUtil.logException("Unexpected exception while loading implementation for " + serviceName, e);
                     throw e;
                 }
             }
             return false;
         }
-
-        @Override
-        public Spliterator<S> trySplit() {
-            return null;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-
-        @Override
-        public int characteristics() {
-            return NONNULL | IMMUTABLE;
-        }
-
     }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceRegistry.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceRegistry.java
deleted file mode 100644
index b73b5b6f8f..0000000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceRegistry.java
+++ /dev/null
@@ -1,81 +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.lang.invoke.MethodHandles.Lookup;
-import java.util.List;
-import java.util.Map;
-import java.util.ServiceLoader;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-/**
- * Registry for service instances loaded from {@link ServiceLoader}. This abstracts the differences between using a flat
- * classpath versus a module path.
- *
- * @since 3.0.0
- */
-@InternalApi
-public final class ServiceRegistry {
-    private static final Lazy<ServiceRegistry> INSTANCE = Lazy.relaxed(ServiceRegistry::new);
-
-
-    /**
-     * Returns the singleton ServiceRegistry instance.
-     */
-    public static ServiceRegistry getInstance() {
-        return INSTANCE.get();
-    }
-
-    private final Map<Class<?>, List<?>> registry = new ConcurrentHashMap<>();
-
-    private ServiceRegistry() {
-    }
-
-    /**
-     * Gets service instances loaded from the calling context and any previously registered bundle services. The {@code loaderCallerContext} parameter is
-     * provided to ensure the caller can specify which calling function context to
-     * load services.
-     *
-     * @param serviceType         service class
-     * @param lookup              MethodHandle lookup created in same module as caller context
-     *                            to use for loading services
-     * @param validator           if non-null, used to validate service instances,
-     *                            removing invalid instances from the returned list
-     * @param <S>                 type of service
-     * @return loaded service instances
-     */
-    public <S> List<S> getServices(final Class<S> serviceType, final Lookup lookup, final Predicate<S> validator) {
-        return getServices(serviceType, lookup, validator, true);
-    }
-
-    /**
-     * Set 'verbose' to false if the `StatusLogger` is not available yet.
-     */
-    <S> List<S> getServices(final Class<S> serviceType, final Lookup lookup, final Predicate<S> validator, final boolean verbose) {
-        final List<?> existing = registry.get(serviceType);
-        if (existing != null) {
-            return Cast.cast(existing);
-        }
-        final List<S> services = ServiceLoaderUtil.loadServices(serviceType, lookup, false, verbose)
-                .filter(validator != null ? validator : unused -> true)
-                .collect(Collectors.toList());
-        final List<S> oldValue = Cast.cast(registry.putIfAbsent(serviceType, services));
-        return oldValue != null ? oldValue : services;
-    }
-}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 10feed227d..bb4befedec 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -16,7 +16,6 @@
  */
 package org.apache.logging.log4j.core.config;
 
-import java.lang.invoke.MethodHandles;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -25,6 +24,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -35,7 +35,6 @@ import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
-import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Appender;
@@ -88,12 +87,12 @@ import org.apache.logging.log4j.util.Lazy;
 import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.PropertyEnvironment;
-import org.apache.logging.log4j.util.ServiceRegistry;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
 
 /**
  * The base Configuration. Many configuration implementations will extend this class.
  */
-@ServiceConsumer(value = ScriptManagerFactory.class, resolution = Resolution.OPTIONAL)
+@ServiceConsumer(ScriptManagerFactory.class)
 public abstract class AbstractConfiguration extends AbstractFilterable implements Configuration {
 
     /**
@@ -291,9 +290,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
 
     private void initializeScriptManager() {
         try {
-            ServiceRegistry.getInstance()
-                    .getServices(ScriptManagerFactory.class, MethodHandles.lookup(), null)
-                    .stream()
+            ServiceLoaderUtil.safeStream(ServiceLoader.load(ScriptManagerFactory.class, AbstractConfiguration.class.getClassLoader()))
                     .findFirst()
                     .ifPresent(factory -> setScriptManager(factory.createScriptManager(this, getWatchManager())));
         } catch (final LinkageError | Exception e) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index db32a6852f..373df99619 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@ -16,17 +16,16 @@
  */
 package org.apache.logging.log4j.core.impl;
 
-import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceLoader;
 import java.util.concurrent.ConcurrentLinkedDeque;
 
 import aQute.bnd.annotation.Cardinality;
-import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.ContextDataInjector;
@@ -34,7 +33,7 @@ import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.util.ContextDataProvider;
 import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
-import org.apache.logging.log4j.util.ServiceRegistry;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
 import org.apache.logging.log4j.util.StringMap;
 
 /**
@@ -52,7 +51,7 @@ import org.apache.logging.log4j.util.StringMap;
  * @see ContextDataInjectorFactory
  * @since 2.7
  */
-@ServiceConsumer(value = ContextDataProvider.class, resolution = Resolution.OPTIONAL, cardinality = Cardinality.MULTIPLE)
+@ServiceConsumer(value = ContextDataProvider.class, cardinality = Cardinality.MULTIPLE)
 public class ThreadContextDataInjector {
 
     /**
@@ -65,13 +64,14 @@ public class ThreadContextDataInjector {
 
     private static List<ContextDataProvider> getServiceProviders() {
         final List<ContextDataProvider> providers = new ArrayList<>();
-        final List<ContextDataProvider> services = ServiceRegistry.getInstance()
-                .getServices(ContextDataProvider.class, MethodHandles.lookup(), null);
-        for (final ContextDataProvider provider : services) {
-            if (providers.stream().noneMatch((p) -> p.getClass().isAssignableFrom(provider.getClass()))) {
-                providers.add(provider);
-            }
-        }
+        final ServiceLoader<ContextDataProvider> serviceLoader =
+                ServiceLoader.load(ContextDataProvider.class, ThreadContextDataInjector.class.getClassLoader());
+        ServiceLoaderUtil.safeStream(serviceLoader)
+                .forEachOrdered(provider -> {
+                    if (providers.stream().noneMatch((p) -> p.getClass().isAssignableFrom(provider.getClass()))) {
+                        providers.add(provider);
+                    }
+                });
         return Collections.unmodifiableList(providers);
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
index 9ed1f2dc5a..3e271182c8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
@@ -17,21 +17,21 @@
 package org.apache.logging.log4j.core.util;
 
 import java.io.File;
-import java.lang.invoke.MethodHandles;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.ServiceLoader;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 import aQute.bnd.annotation.Cardinality;
-import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.AbstractLifeCycle;
@@ -39,7 +39,7 @@ import org.apache.logging.log4j.core.config.ConfigurationScheduler;
 import org.apache.logging.log4j.plugins.Inject;
 import org.apache.logging.log4j.plugins.Singleton;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.ServiceRegistry;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
 
 /**
  * Manages {@link FileWatcher}s.
@@ -48,7 +48,7 @@ import org.apache.logging.log4j.util.ServiceRegistry;
  * @see ConfigurationScheduler
  */
 @Singleton
-@ServiceConsumer(value = WatchEventService.class, resolution = Resolution.OPTIONAL, cardinality = Cardinality.MULTIPLE)
+@ServiceConsumer(value = WatchEventService.class, cardinality = Cardinality.MULTIPLE)
 public class WatchManager extends AbstractLifeCycle {
 
     private static final class ConfigurationMonitor {
@@ -140,8 +140,8 @@ public class WatchManager extends AbstractLifeCycle {
     @Inject
     public WatchManager(final ConfigurationScheduler scheduler) {
         this.scheduler = Objects.requireNonNull(scheduler, "scheduler");
-        eventServiceList = ServiceRegistry.getInstance()
-                .getServices(WatchEventService.class, MethodHandles.lookup(), null);
+        eventServiceList = ServiceLoaderUtil.safeStream(ServiceLoader.load(WatchEventService.class, WatchManager.class.getClassLoader()))
+                .collect(Collectors.toList());
     }
 
     public void checkFiles() {
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DI.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DI.java
index f831f3d262..1a9a538c55 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DI.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DI.java
@@ -16,12 +16,12 @@
  */
 package org.apache.logging.log4j.plugins.di;
 
-import java.lang.invoke.MethodHandles;
 import java.util.Comparator;
+import java.util.ServiceLoader;
 
 import org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor;
 import org.apache.logging.log4j.plugins.util.OrderedComparator;
-import org.apache.logging.log4j.util.ServiceRegistry;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
 
 /**
  * Factory for {@linkplain InstanceFactory instance factories}.
@@ -75,9 +75,7 @@ public final class DI {
      * @param factory the instance factory to initialize
      */
     public static void initializeFactory(final ConfigurableInstanceFactory factory) {
-        ServiceRegistry.getInstance()
-                .getServices(ConfigurableInstanceFactoryPostProcessor.class, MethodHandles.lookup(), null)
-                .stream()
+        ServiceLoaderUtil.safeStream(ServiceLoader.load(ConfigurableInstanceFactoryPostProcessor.class, DI.class.getClassLoader()))
                 .sorted(Comparator.comparing(ConfigurableInstanceFactoryPostProcessor::getClass, OrderedComparator.INSTANCE))
                 .forEachOrdered(processor -> processor.postProcessFactory(factory));
     }