资讯专栏INFORMATION COLUMN

Log42j 源代码分析:plugin(插件)机制

learning / 1593人阅读

摘要:前言使用插件机制加载各种组件,本文简要分析插件机制实现注解注解提供了一种便捷的方法将一个类声明成的插件,比如,单例类用来保存插件信息,暴露了一些方法从配置文件中加载内置插件,使用了单例设计模式线程安全的数据结构使用了一些多线程编程的最佳实践

前言

log4j2 使用插件机制加载各种组件:appender, logger .etc,本文简要分析 log4j2 插件机制实现

Plugin Annotation(注解)

Plugin 注解提供了一种便捷的方法将一个类声明成 log4j2 的插件,比如

@Plugin(name = "Console", category = "Core", elementType = "appender", printObject = true)
public final class ConsoleAppender extends
        AbstractOutputStreamAppender {
    ...
}

name,name of the plugin

category, category to place the plugin under

name of the corresponding category of elements this plugin belongs under

Plugin Registry 单例

PluginRegistry 类用来保存插件信息,暴露了一些方法从配置文件中加载(内置)插件,使用了单例设计模式

private static volatile PluginRegistry INSTANCE;

private static final Object INSTANCE_LOCK = new Object();

private PluginRegistry() {
}

public static PluginRegistry getInstance() {
    PluginRegistry result = INSTANCE;
    if (result == null) {
        synchronized(INSTANCE_LOCK) {
            result = INSTANCE;
            if (result == null) {
                INSTANCE = result = new PluginRegistry();
            }
        }
    }
}
线程安全的数据结构

PluginRegistry 使用了一些 Java 多线程编程的最佳实践:

使用 AtomicReference 类的 CAS(compare and set)操作,避免在多线程环境下 插件配置 被多次加载

使用 ConcurrentMapHash 类替代 HashMap 提供线程安全的 map

PluginType 类用来描述插件,比如插件对应的 class

    /**
     * Contains plugins found in Log4j2Plugins.dat cache files in the main CLASSPATH.
     */
    private final AtomicReference>>> pluginsByCategoryRef =
        new AtomicReference<>();

    /**
     * Contains plugins found in Log4j2Plugins.dat cache files in OSGi Bundles.
     */
    private final ConcurrentMap>>> pluginsByCategoryByBundleId =
        new ConcurrentHashMap<>();

    /**
     * Contains plugins found by searching for annotated classes at runtime.
     */
    private final ConcurrentMap>>> pluginsByCategoryByPackage =
        new ConcurrentHashMap<>();

log4j2Plugins.dat 是插件描述文件,内部插件描述文件位于:

log4j-core-2.5.jar
    META-INF
        org.apache.logging.log4j.core.config.plugins
            Log4j2Plugins.dat
加载插件

PluginRegistry 中和加载扫描插件相关的方法

loadFromMainClassLoader,加载内部插件

loadFromBundle,osgi相关

loadFromPackage,加载指定 package(包)中的插件

加载内部插件
    public Map>> loadFromMainClassLoader() {
        final Map>> existing = pluginsByCategoryRef.get();
        // 如果 get 方法返回非空,说明已经通过 main class loader 加载过插件配置
        if (existing != null) {
            // already loaded
            return existing;
        }
        // 从配置文件加载 插件配置
        final Map>> newPluginsByCategory =    
            decodeCacheFiles(Loader.getClassLoader());
        // CAS
        if (pluginsByCategoryRef.compareAndSet(null, newPluginsByCategory)) {
            return newPluginsByCategory;
        }
        return pluginsByCategoryRef.get();
    }
加载指定包中插件
public Map>> loadFromPackage(final String pkg) {
    // 参数校验
    if (Strings.isBlank(pkg)) {
        return Collections.emptyMap();
    }

    // 如果 pkg 已经被加载过直接返回
    Map>> existing = pluginByCategoryByPackage.get(pkg);
    if (existing != null) {
        return existing;
    }

    // 加载 pkg

    // 线程安全的 put if absent 操作(类似 CAS)
    existing = pluginsByCategoryByPackage.putIfAbsent(pkg, newPluginsByCategory);
    if (existing != null) {
        return existing;
    }
    return newPluginsByCategory;
}
PluginManager

PluginManager 类用来加载和管理所有的插件,每一个 category(类别)都有一个对应的 PluginManager

public PluginManager(final String category) {
    this.category = category;
}

collectPlugins 方法用于加载插件(描述信息)

public void collectPlugins(final List packages) {
    ...
}
总结

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66792.html

相关文章

  • Log42j 代码分析:日志回滚

    摘要:前言一般都会对应用程序日志做回滚处理,本文简要分析日志回滚实现触发策略使用接口来抽象日志回滚触发策略,使用了设计模式方法用于初始化策略,方法用于判断是否需要回滚,接口的不同实现类对应不同的策略组合模式,聚合不同的策略类基于时间的回滚策略基于 前言 一般都会对应用程序日志做回滚处理,本文简要分析 log4j2 日志回滚实现 触发策略 log4j2 使用 TriggeringPolity ...

    libin19890520 评论0 收藏0
  • webpack系列-插件机制杂记

    摘要:系列文章系列第一篇基础杂记系列第二篇插件机制杂记系列第三篇流程杂记前言本身并不难,他所完成的各种复杂炫酷的功能都依赖于他的插件机制。的插件机制依赖于一个核心的库,。是什么是一个类似于的的库主要是控制钩子函数的发布与订阅。 系列文章 Webpack系列-第一篇基础杂记 Webpack系列-第二篇插件机制杂记 Webpack系列-第三篇流程杂记 前言 webpack本身并不难,他所完成...

    Neilyo 评论0 收藏0
  • video.js 源码分析(JavaScript)

    摘要:语法部分采用的是标准。那么整个播放器是怎么把播放器的加载到中的呢在的构造函数里可以看到先生成,然后初始化父类遍历属性,将中的类实例化并将对应的嵌入到的属性中,最后在的构造函数中直接挂载到标签的父级上。 video.js 源码分析(JavaScript) 组织结构 继承关系 运行机制 插件的运行机制 插件的定义 插件的运行 控制条是如何运行的 UI与JavaScript对象的...

    Neilyo 评论0 收藏0
  • video.js 源码分析(JavaScript)

    摘要:语法部分采用的是标准。那么整个播放器是怎么把播放器的加载到中的呢在的构造函数里可以看到先生成,然后初始化父类遍历属性,将中的类实例化并将对应的嵌入到的属性中,最后在的构造函数中直接挂载到标签的父级上。 video.js 源码分析(JavaScript) 组织结构 继承关系 运行机制 插件的运行机制 插件的定义 插件的运行 控制条是如何运行的 UI与JavaScript对象的...

    simpleapples 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<