Over time, we collected many places in the codebase that accept an override by specifying a class name through a system property. These typically worked by guessing at an appropriate ClassLoader to use to load the class and then using reflection to instantiate it. This pattern is problematic in module systems like the Java module system and OSGi due to stronger encapsulation guarantees. As we've already implemented for plugins, anything else remaining that customizes class selection based on system properties should be updated to use java.util.ServiceLoader (when customizing in log4j-api) or specified in bundle classes installed via a service loader (which is also where some of the old system properties customizations are currently supported and can be simplified).
In general, the goal of this is to eliminate the use of LoaderUtil::load and any other implicit ClassLoader usage.
For some concrete examples, as I've worked on this, I've found the following interfaces that can be specified by system properties which are generally being refactored into what I said above.
Log4j API
The following interfaces are being loaded through service loader provider classes. These are similar in a way to the previous iteration of the Provider service class which grouped some of these things together.
org.apache.logging.log4j.spi.LoggerContextFactory
org.apache.logging.log4j.spi.ThreadContextMap
org.apache.logging.log4j.spi.ThreadContextStack
org.apache.logging.log4j.message.MessageFactory
org.apache.logging.log4j.message.FlowMessageFactory
There are some other service loader classes in the API, but they're either new or were already using service loading.
Log4j Core
The following interfaces either allow for overriding a default using a system property or are only configured through a system property. These should be updated to use bindings (or service loaders if that's not possible).
com.lmax.disruptor.ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper> - AsyncLogger-specific exception handler
com.lmax.disruptor.ExceptionHandler<RingBufferLogEvent> - AsyncLoggerContext-specific exception handler
org.apache.logging.log4j.core.async.AsyncQueueFullPolicy
org.apache.logging.log4j.core.async.AsyncWaitStrategyFactory
org.apache.logging.log4j.core.util.AuthorizationProvider
org.apache.logging.log4j.core.time.Clock
org.apache.logging.log4j.core.config.ConfigurationFactory
org.apache.logging.log4j.core.config.ReliabilityStrategy
org.apache.logging.log4j.core.ContextDataInjector
- Reflective instantiation of a
org.apache.logging.log4j.util.StringMap for ContextDataFactory
Other
There are a few standalone modules that use LoaderUtil::loadClass for things that can be ported to use DI directly. There are some other places still using LoaderUtil or Loader that should be cleaned up alongside all this.
Over time, we collected many places in the codebase that accept an override by specifying a class name through a system property. These typically worked by guessing at an appropriate
ClassLoaderto use to load the class and then using reflection to instantiate it. This pattern is problematic in module systems like the Java module system and OSGi due to stronger encapsulation guarantees. As we've already implemented for plugins, anything else remaining that customizes class selection based on system properties should be updated to usejava.util.ServiceLoader(when customizing in log4j-api) or specified in bundle classes installed via a service loader (which is also where some of the old system properties customizations are currently supported and can be simplified).In general, the goal of this is to eliminate the use of
LoaderUtil::loadand any other implicitClassLoaderusage.For some concrete examples, as I've worked on this, I've found the following interfaces that can be specified by system properties which are generally being refactored into what I said above.
Log4j API
The following interfaces are being loaded through service loader provider classes. These are similar in a way to the previous iteration of the
Providerservice class which grouped some of these things together.org.apache.logging.log4j.spi.LoggerContextFactoryorg.apache.logging.log4j.spi.ThreadContextMaporg.apache.logging.log4j.spi.ThreadContextStackorg.apache.logging.log4j.message.MessageFactoryorg.apache.logging.log4j.message.FlowMessageFactoryThere are some other service loader classes in the API, but they're either new or were already using service loading.
Log4j Core
The following interfaces either allow for overriding a default using a system property or are only configured through a system property. These should be updated to use bindings (or service loaders if that's not possible).
com.lmax.disruptor.ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper>- AsyncLogger-specific exception handlercom.lmax.disruptor.ExceptionHandler<RingBufferLogEvent>- AsyncLoggerContext-specific exception handlerorg.apache.logging.log4j.core.async.AsyncQueueFullPolicyorg.apache.logging.log4j.core.async.AsyncWaitStrategyFactoryorg.apache.logging.log4j.core.util.AuthorizationProviderorg.apache.logging.log4j.core.time.Clockorg.apache.logging.log4j.core.config.ConfigurationFactoryorg.apache.logging.log4j.core.config.ReliabilityStrategyorg.apache.logging.log4j.core.ContextDataInjectororg.apache.logging.log4j.util.StringMapforContextDataFactoryOther
There are a few standalone modules that use
LoaderUtil::loadClassfor things that can be ported to use DI directly. There are some other places still usingLoaderUtilorLoaderthat should be cleaned up alongside all this.