一、log4j2插件plugins简介

# @Plugin的使用请参考下一章日志框架LOG4J2系列五——@Plugin插件实现不同线打印日志

Log4j 1.x 允许对指定的大多数配置声明的类属性进行扩展,例如想要自定义模板匹配器需要通过代码来扩展PatternLayout类功能。而log4j2的目的是使这样的功能扩展变得更容易。在 Log4j 2 中,通过在类声明上添加@Plugin注解来声明一个自定义插件。在初始化期间,Configuration将调用PluginManager来加载内置的 Log4j 插件以及所有自定义插件。 PluginManager 会在以下的五个位置查找来找到插件:

  • Classpath 下的序列化插件列表文件,这些文件是在构建过程中自动生成的
  • (仅 OSGi)每个激活的 OSGi bundle 包中的序列化插件列表文件。一个BundleListener log4j-core 启动后被激活以继续检查新的 bundle(参考:OSGi 系列(三)之 bundle 详解)。
  • 由 log4j.plugin.packages 系统属性指定的包,用逗号分隔。
  • 通过静态方法PluginManager.addPackages添加的包(在进行 Log4j 配置之前)
  • 在 log4j2 配置文件中声明的包

如果多个插件指定了相同的(不区分大小写)名称,则上面的加载顺序决定将使用哪个插件。例如,要覆盖内置FileAppender类提供的文件插件,需要将插件放在log4j-core.jar前面类路径中的JAR中。不建议这样做;插件名称冲突将导致发出警告。请注意,在OSGi环境中,扫描捆绑包以查找插件的顺序通常与将捆绑包安装到框架中的顺序相同。请参阅getBundles()SynchronousBundleListener。简而言之,在OSGi环境中,名称冲突甚至更不可预测

序列化的插件列表文件由log4j-core组件中包含的注释处理器生成,它将自动扫描代码中的log4j 2插件,并在处理过的类中输出元数据文件。不需要做任何额外的事情来实现这一操作,Java编译器会将自动在类路径上拾取注释处理器,除非显式禁用。在这种情况下,向构建过程中添加另一个只使用Log4j 2注释处理器类org.apache.logging.Log4j.core.config.plugins.processor.PluginProcessor处理注释处理的编译器过程是很重要的。要使用ApacheMaven执行此操作,请将以下执行添加到Maven编译器插件(版本2.2或更高版本)构建插件中

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.1</version>
  <executions>
    <execution>
      <id>log4j-plugin-processor</id>
      <goals>
        <goal>compile</goal>
      </goals>
      <phase>process-classes</phase>
      <configuration>
        <proc>only</proc>
        <annotationProcessors>
          <annotationProcessor>org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor</annotationProcessor>
        </annotationProcessors>
      </configuration>
    </execution>
  </executions>
</plugin>

下面将具体介绍一下log4j2的插件

二、Core

Core插件是指那些由配置文件中的元素直接表示的插件,例如Appender、Layout、Logger或Filter。每个Core插件都必须声明一个用@PluginFactory或@PluginBuilderFactory 注释的静态方法。@PluginFactory用于提供所有选项作为方法参数的静态工厂方法,@PluginBuilderFactory 用于构造一个新的Builder类,其字段用于注入属性和子节点。要允许配置将正确的参数传递给方法,方法的每个参数都必须注释为以下属性类型之一。

  • PluginAttribute
    必须使用TypeConverter从字符串转换参数。大多数内置类型已经得到支持,但也可以提供定制的TypeConverter插件以获得更多类型支持。注意,PluginBuilderAttribute可以在生成器类字段中使用,这是提供默认值的一种更简单的方法。
  • PluginElement
    该参数可以表示本身具有可配置参数的复杂对象。这还支持注入元素数组。
  • PluginConfiguration
    当前配置对象将作为参数传递给插件。
  • PluginNode
    正在解析的当前节点将作为参数传递给插件。
  • PluginValue
    当前节点的值或其名为value的属性。

每个属性或元素注释必须包含配置中必须存在的名称,以便将配置项与其各自的参数相匹配。对于插件生成器,如果注释中未指定名称,则默认情况下将使用字段的名称。Log4j Core中有几十个插件,可以用作更复杂场景的示例,包括分层构建器类(例如,请参阅FileAppender)。有关更多详细信息,请参阅 Extending Log4j with Plugin Builders

  • Constraint Validators
    插件工厂字段和参数可以在运行时使用受Bean验证规范启发的约束验证器自动验证。以下注释捆绑在Log4j中,但也可以创建自定义约束验证器。
    • Required
      此注解验证值是否为非空。这包括检查null以及其他几个场景:空CharSequence对象、空数组、空集合实例和空映射实例。
    • ValidHost
      此注释验证值是否对应于有效的主机名。这使用与InetAddress::getByName相同的验证。
    • ValidPort
      此批注验证值是否对应于介于0和65535之间的有效端口号。

三、Converters

PatternLayout能够根据指定规则进行匹配。每个转换器必须在@Plugin注释中将其类别指定为“converter”,并具有一个静态newInstance方法,该方法接受字符串数组作为其唯一参数,并返回转换器实例,并且必须具有@ConverterKeys注释,该注释包含将导致选择转换器的转换器模式数组。用于处理LogEvents的转换器必须扩展LogEventPatternConverter类,并且必须实现接受LogEvent和StringBuilder作为参数的format方法。转换器应将其操作结果输出到StringBuilder。

第二种类型的转换器是FileConverter,它必须在@Plugin注释的category属性中指定“FileConverter”。虽然类似于LogEventPatternConverter,但这些转换器将有两种变体,而不是单一的格式方法;一个接受对象,另一个接受对象数组而不是LogEvent。两者都以与LogEventPatternConverter相同的方式附加到提供的StringBuilder。RollingFileAppender通常使用这些转换器来构造要登录到的文件的名称。

如果多个转换器指定相同的转换器键,则上面的加载顺序决定将使用哪个转换器键。例如,要覆盖内置DatePatternConverter类提供的%date转换器,您需要将插件放在G4J-core.JAR前面的类路径中的JAR文件中。不建议这样做;pattern ConverterKeys碰撞将导致发出警告。尝试为自定义图案转换器使用唯一的ConverterKey。

四、KeyProviders

Log4j中的一些组件可以提供执行数据加密的能力。这些组件需要密钥来执行加密。应用程序可以通过创建实现SecretKeyProvider接口的类来提供密钥

五、Lookups

查找可能是所有插件中最简单的插件。他们必须在插件注释中将其类型声明为“Lookup”,并且必须实现StrLookup接口。他们将有两种方法;接受字符串键并返回字符串值的查找方法,以及接受LogEvent和字符串键并返回字符串的第二个查找方法。可以通过指定${name:key}来引用查找,其中name是插件注释中指定的名称,key是要查找的项的名称。

六、TypeConverters

TypeConverters是一种元插件,用于在插件工厂方法参数中将字符串转换为其他类型。其他插件已经可以通过@PluginElement注释注入;现在,类型转换系统支持的任何类型都可以在@PluginAttribute参数中使用。支持按需转换枚举类型,不需要自定义TypeConverter类。大量内置Java类已经得到支持;有关更详尽的列表,请参见TypeConverters。

与其他插件不同,TypeConverter的插件名纯粹是修饰性的。通过类型接口而不是仅通过类<?>对象查找适当的类型转换器。请注意,TypeConverter插件必须具有默认构造函数。

七、Developer Notes

如果插件类实现了集合或映射,则不使用工厂方法。相反,使用默认构造函数实例化该类,并将所有子配置节点添加到集合或映射中。

@Plugin的使用请参考下一章日志框架LOG4J2系列五——@Plugin插件实现不同线打印日志

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐