[ https://issues.apache.org/jira/browse/LOG4J2-2803?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17357952#comment-17357952 ]
Gary D. Gregory commented on LOG4J2-2803: ----------------------------------------- Is an unstated goal here to support exisiting configuration files? > Create standardized scopes and dependency injection API > ------------------------------------------------------- > > Key: LOG4J2-2803 > URL: https://issues.apache.org/jira/browse/LOG4J2-2803 > Project: Log4j 2 > Issue Type: Epic > Components: Configuration, Core, Plugins > Reporter: Matt Sicker > Assignee: Matt Sicker > Priority: Major > Fix For: 3.0.0 > > > h2. Context > The existing plugin system revolves around {{@Plugin}} annotations which > group together configurable interfaces into categories. The category of a > plugin typically determines the configuration and instantiation strategy for > the plugin classes involved which leads to some ad hoc methods for different > plugins to obtain or configure different aspects of the system. All classes > that are included in the plugin system can be queried at runtime by > constructing a {{PluginManager}} with the category name as its constructor > argument. To date, there are a few plugin categories (case-insensitive): > * {{Core}}: used for configuration elements in config files for general core > plugins like appenders, filters, layouts, etc. These are provided values from > parsed configuration nodes and can also obtain the {{Configuration}} instance > to access other services. > * {{Level}}: used for specifying custom log levels so that they can be > instantiated early enough for configurations to make use of it. > * {{ConfigurationFactory}}: used for parsing and validating configuration > sources in some format into a configuration node tree which is transformed > into a {{Configuration}}. Also useful for programmatic configuration. > * {{Lookup}}: used for variable interpolation in strings via {{StrLookup}} > classes. > * {{TypeConverter}}: used for converting strings into other objects. Mostly > useful for conversion of plugin attributes into common types along with use > in certain core plugins such as database column mappers. > * {{Converter}}: used for pattern layout conversion keys. These are used for > formatting log event info into a layout. > * {{Watcher}}: used for watching configuration sources for changes in order > to allow for reconfiguration. > Then there are some system-wide plugin-like classes that can be specified via > system properties including: > * {{ClockFactory}}: controls {{Clock}} instances for obtaining the current > time. Mostly useful in testing and scenarios where approximate time is more > useful than exact time. > * {{LogEventFactory}}: constructs {{LogEvent}} instances for a given log > message and parameters. Useful for implementing different allocation > strategies for log events. > * {{MergeStrategy}}: used for composite configurations. > * {{ContextSelector}}: used for obtaining a {{LoggerContext}} for an > invocation context when initializing or obtaining {{Logger}} instances. By > default, this maps contexts to class loaders, and additional strategies are > available including async loggers, a singleton context, a JNDI-lookup-based > context, and an OSGi bundle context. > * {{LoggerContextFactory}}: used for binding a logging implementation to the > Logging API. > * {{ShutdownCallbackRegistry}}: used for registering a logging system > cleanup shutdown callback in various systems. The default strategy hooks in > to the {{Runtime}} shutdown threads API. > * {{ContextDataInjector}}: used for adding initial context data into the > {{ThreadContext}} of a {{LogEvent}}. > h2. Proposal > This system grew organically over time, and after identifying various > duplicated plugin functionality around the codebase, the plugin system should > be overhauled along the lines of a more standard {{@Inject}}-style dependency > injection framework. By adopting more conventional DI patterns, this will > remove the need for ad hoc plugin mechanisms in different subsystems, allow > for more flexible declarations of plugins by specifying direct classes needed > by plugins rather than doing manual lookups on the {{Configuration}} > instance, allow for smarter initialization strategies to minimize startup > time and resource usage based on configurations rather than eagerly loading > plugins, make it simpler to write unit tests, and make it generally simpler > to write and maintain plugins without requiring deep expertise of esoteric > subsystems. > Taking inspiration from [CDI|https://docs.jboss.org/cdi/api/2.0/], > [@Inject|https://docs.oracle.com/javaee/6/api/javax/inject/Inject.html], and > [Guice|https://github.com/google/guice], the plugin system should be updated > to a new API that is broken up into a few useful concepts: > * Beans: beans are analogous to Java classes with additional metadata to > enable lifecycle management and dependency injection. Unlike a normal Java > class, a bean has injection points (like constructor arguments, methods, and > fields) where other managed instances can be injected at runtime based on the > currently configured beans. As these are managed, they can have > post-construct and pre-destruct callbacks for further lifecycle customization. > ** Scopes: scopes control where the instances are stored or to what > lifecycle they're tied to. At minimum, this includes dependent-scoped > (creates new instances for every injection point) and singleton-scoped > (creates and maintains a single instance for all injection points). In > general DI frameworks, other scopes include things like HTTP sessions and > HTTP requests. For this framework, the {{ContextSelector}} configuration API > corresponds to a {{Configuration}} scope. > ** Qualifiers: qualifiers add metadata to a bean besides its type to match > on for injection. Typical qualifiers are names. Plugin configuration > attribute names would likely make a good match here as another example. > * Injection points: in order to obtain injectable values into a bean > instance, injection points control how these instances are bound to the bean. > This is essentially the strategy for binding data to fields, constructors, > and methods. > * Providers: providers are analogous to plugin builders in that they specify > how to create an instance of type {{T}} given some plugin builder class > {{Builder<T> implements Provider<T>}}. > * Producer and disposer methods: beans can specify producer and disposer > methods as alternative ways to specify how to construct a bean instance. > These are analogous to plugin factory methods. > Adopting such a plugin system based on beans, all the plugins that currently > require either a {{Configuration}} or {{Node}} instance to do anything should > be refactored to rely on proper dependency injection. This should be used to > replace as many disparate dependency injection and configuration systems as > possible to reduce the complexity required to implement plugins that rely on > shared components. > h2. Additional Details > > Beyond the dependency injection API itself, this epic is motivated by the > following goals: > * Simplify plugin classes that currently require manual method calls to > {{Configuration}} or {{Node}}. > * Unify the various ad hoc dependency injection for configuration-scoped or > singleton-scoped classes (the latter which are overridden via system > properties) including: > ** {{StrSubstitutor}} > ** {{ConfigurationScheduler}} (or scheduled tasks in general) > ** {{ScriptManager}} > ** {{WatchManager}} > ** {{NanoClock}} > ** {{ShutdownCallbackRegistry}} > ** {{Clock}} > ** {{ContextSelector}} > ** {{ConfigurationFactory}} > ** {{LogEventFactory}} > ** {{ContextDataFactory}} > * Make dependencies between classes more explicit via inversion of control > which allows for easier testing and modularity. > * Avoid the use of manual configuration handling at the API level of any > plugins including basic string parsing (as currently supported through the > {{TypeConverter}} API), class loading from strings, and ad hoc reflection. > This relates to the changes made in LOG4J2-2621 and LOG4J2-1917. > * Provide smart initialization logic to continue (or maintain) improvements > to startup time and avoid loading plugins that aren't referenced in the > loaded configuration. > * Provide scopes for other ad hoc scopes/contexts used in various plugins > such as HTTP request, HTTP session, servlet context, etc. -- This message was sent by Atlassian Jira (v8.3.4#803005)