[ 
https://issues.apache.org/jira/browse/LOG4J2-2803?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17357954#comment-17357954
 ] 

Gary D. Gregory commented on LOG4J2-2803:
-----------------------------------------

I might be playing devil's advocate here but why would we not reuse an existing 
framework here?

 

> 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)

Reply via email to