前言

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

Plugin Annotation(注解)

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

@Plugin(name = "Console", category = "Core", elementType = "appender", printObject = true)
public final class ConsoleAppender extendsAbstractOutputStreamAppender<OutputStreamManager> {...
}
  • 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<Map<String, List<PluginType<?>>>> pluginsByCategoryRef =new AtomicReference<>();/*** Contains plugins found in Log4j2Plugins.dat cache files in OSGi Bundles.*/private final ConcurrentMap<Long, Map<String, List<PluginType<?>>>> pluginsByCategoryByBundleId =new ConcurrentHashMap<>();/*** Contains plugins found by searching for annotated classes at runtime.*/private final ConcurrentMap<String, Map<String, List<PluginType<?>>>> pluginsByCategoryByPackage =new ConcurrentHashMap<>();

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

log4j-core-2.5.jarMETA-INForg.apache.logging.log4j.core.config.pluginsLog4j2Plugins.dat

加载插件

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

  • loadFromMainClassLoader,加载内部插件

  • loadFromBundle,osgi相关

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

加载内部插件

    public Map<String, List<PluginType<?>>> loadFromMainClassLoader() {final Map<String, List<PluginType<?>>> existing = pluginsByCategoryRef.get();// 如果 get 方法返回非空,说明已经通过 main class loader 加载过插件配置if (existing != null) {// already loadedreturn existing;}// 从配置文件加载 插件配置final Map<String, List<PluginType<?>>> newPluginsByCategory =    decodeCacheFiles(Loader.getClassLoader());// CASif (pluginsByCategoryRef.compareAndSet(null, newPluginsByCategory)) {return newPluginsByCategory;}return pluginsByCategoryRef.get();}

加载指定包中插件

public Map<String, List<PluginType<?>>> loadFromPackage(final String pkg) {// 参数校验if (Strings.isBlank(pkg)) {return Collections.emptyMap();}// 如果 pkg 已经被加载过直接返回Map<String, List<PluginType<?>>> 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<String> packages) {...
}

总结

Log42j 源代码分析:plugin(插件)机制相关推荐

  1. 如何使用MyBatis的plugin插件实现多租户的数据过滤?

    如何实现多租户数据隔离 在中台服务或者saas服务中,当多租户入驻时,如何保证不同租户的数据隔离性呢?通常的解决方法有三种,分别如下: 一个租户一个独立数据库,这种方案的用户数据隔离级别最高,安全性最 ...

  2. Apache Nutch 1.3 学习笔记十(插件机制分析)

    1. 一些对象说明 PluginRepository:这是一个用于存储所有插件描述对象(PluginDescriptor),插件扩展点(ExtensionPoint)和被激活的插件. PluginDe ...

  3. MyBatis 源码分析 - 插件机制

    1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...

  4. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  5. 通过分析 JDK 源代码研究 Hash 存储机制

    http://www.ibm.com/developerworks/cn/java/j-lo-hash/ 通过分析 JDK 源代码研究 Hash 存储机制 HashMap 和 HashSet 是 Ja ...

  6. 通过分析 JDK 源代码研究 Hash 存储机制--转载

    通过 HashMap.HashSet 的源代码分析其 Hash 存储机制 集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象 ...

  7. Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

    原文地址: http://blog.csdn.net/luoshengyang/article/details/6629298 在前面一篇文章浅谈Android系统进程间通信(IPC)机制Binder ...

  8. Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...

  9. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)...

    注意,这里的参数reply = 0,表示这是一个BC_TRANSACTION命令.         前面我们提到,传给驱动程序的handle值为0,即这里的tr->target.handle = ...

最新文章

  1. Galaxy 生信平台(二):生产环境部署
  2. 把 Bug 晾几天就能解决了!!! | 每日趣闻
  3. js轮播图片小圆点变化_原生js实现轮播图(两种方法)
  4. 文末福利 | Python3 网络爬虫:老板,需要特殊服务吗?
  5. button Show most popular product
  6. C++Primer学习笔记:第7章 类
  7. 同时运行多个logstash而kibana监控界面只统计到一个的问题
  8. 华硕笔记本之secure boot
  9. 创建Python数据分析的Docker镜像+Docker自定义镜像commit,Dockerfile方式解析+pull,push,rmi操作...
  10. iOS开发之二维码生成(错误问题小记,微信扫描,长按不识别)
  11. CSS常见面试题(持续更新)
  12. java集合试题_Java练习题 - 集合
  13. 最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)
  14. 二叉树matlab整数规划,基于matlab构造最优二叉树.doc
  15. 数据盘点各城市公积金排名,你能拿多少?
  16. MySQL基础 - 数据类型
  17. 非相参积累 matlab,非相参积累增益,比相参积累增益更难计算?
  18. 西门子1200PLC程序远程上下载,远程在线调试原来是使用了巨控GRM530远程模块
  19. 原生js实现可切换式导航栏
  20. 【音视频基础】(七):CIE颜色空间三之从CIE-XYZ到CIE-xyY

热门文章

  1. WordPress Plupload插件未明跨站脚本漏洞
  2. 在Sharepoint Designer 2007 中加入定制的工作流动作
  3. 性能测试之JMeter配置元件【随机变量】
  4. perfdog 性能狗之Jank
  5. Linux系统下xampp集成环境安装
  6. mp4剪辑器_想学视频剪辑,可是专业的视频软件太难,来试试这软件吧!
  7. 内大计算机学院研究生奖学金,通知 | 【研究生评奖评优】关于做好浙江大学2017-2018学年计算机学院研究生学年小结及评奖评优工作的通知...
  8. 大数据自学好还是培训好?
  9. 【前端规划】来看看我整理的这一份专属技术知识图谱吧~
  10. javascript怎么清除CSS样式?