Log42j 源代码分析:plugin(插件)机制
前言
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(插件)机制相关推荐
- 如何使用MyBatis的plugin插件实现多租户的数据过滤?
如何实现多租户数据隔离 在中台服务或者saas服务中,当多租户入驻时,如何保证不同租户的数据隔离性呢?通常的解决方法有三种,分别如下: 一个租户一个独立数据库,这种方案的用户数据隔离级别最高,安全性最 ...
- Apache Nutch 1.3 学习笔记十(插件机制分析)
1. 一些对象说明 PluginRepository:这是一个用于存储所有插件描述对象(PluginDescriptor),插件扩展点(ExtensionPoint)和被激活的插件. PluginDe ...
- MyBatis 源码分析 - 插件机制
1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...
- Android 中View的绘制机制源代码分析 三
到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...
- 通过分析 JDK 源代码研究 Hash 存储机制
http://www.ibm.com/developerworks/cn/java/j-lo-hash/ 通过分析 JDK 源代码研究 Hash 存储机制 HashMap 和 HashSet 是 Ja ...
- 通过分析 JDK 源代码研究 Hash 存储机制--转载
通过 HashMap.HashSet 的源代码分析其 Hash 存储机制 集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象 ...
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
原文地址: http://blog.csdn.net/luoshengyang/article/details/6629298 在前面一篇文章浅谈Android系统进程间通信(IPC)机制Binder ...
- Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析
[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)...
注意,这里的参数reply = 0,表示这是一个BC_TRANSACTION命令. 前面我们提到,传给驱动程序的handle值为0,即这里的tr->target.handle = ...
最新文章
- Galaxy 生信平台(二):生产环境部署
- 把 Bug 晾几天就能解决了!!! | 每日趣闻
- js轮播图片小圆点变化_原生js实现轮播图(两种方法)
- 文末福利 | Python3 网络爬虫:老板,需要特殊服务吗?
- button Show most popular product
- C++Primer学习笔记:第7章 类
- 同时运行多个logstash而kibana监控界面只统计到一个的问题
- 华硕笔记本之secure boot
- 创建Python数据分析的Docker镜像+Docker自定义镜像commit,Dockerfile方式解析+pull,push,rmi操作...
- iOS开发之二维码生成(错误问题小记,微信扫描,长按不识别)
- CSS常见面试题(持续更新)
- java集合试题_Java练习题 - 集合
- 最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)
- 二叉树matlab整数规划,基于matlab构造最优二叉树.doc
- 数据盘点各城市公积金排名,你能拿多少?
- MySQL基础 - 数据类型
- 非相参积累 matlab,非相参积累增益,比相参积累增益更难计算?
- 西门子1200PLC程序远程上下载,远程在线调试原来是使用了巨控GRM530远程模块
- 原生js实现可切换式导航栏
- 【音视频基础】(七):CIE颜色空间三之从CIE-XYZ到CIE-xyY
热门文章
- WordPress Plupload插件未明跨站脚本漏洞
- 在Sharepoint Designer 2007 中加入定制的工作流动作
- 性能测试之JMeter配置元件【随机变量】
- perfdog 性能狗之Jank
- Linux系统下xampp集成环境安装
- mp4剪辑器_想学视频剪辑,可是专业的视频软件太难,来试试这软件吧!
- 内大计算机学院研究生奖学金,通知 | 【研究生评奖评优】关于做好浙江大学2017-2018学年计算机学院研究生学年小结及评奖评优工作的通知...
- 大数据自学好还是培训好?
- 【前端规划】来看看我整理的这一份专属技术知识图谱吧~
- javascript怎么清除CSS样式?