核心内容摘要
爱情的N种模样:当“避世情侣”遇上“玩咖辣妹”,谁是真玩家?
抽丝剥茧Apache Fesod 读取端的事件驱动架构
入口一个优雅的门面 (Facade)简约而不简单哪怕系统内部再复杂给用户的入口必须足够简单。
Fesod 采用了经典的Facade 模式外观模式。
所有的读取操作都从FesodSheet.read()开始。
// 你的代码FesodSheet.read(file,DemoData.class,listener).sheet().doRead();这就好比你去餐厅点菜你只需要跟服务员Facade说“来份宫保鸡丁”你不需要知道后厨的采购员、切菜工、炒菜师傅Internal Classes是怎么配合的。
核心类关系让我们透视一下这个“门面”背后的指挥系统从图中可以看到ExcelReader只是个传话筒真正的指挥官是ExcelAnalyser而真正的干活主力是ExcelReadExecutor。
流程拆解一次doRead()的奇幻漂流当你按下回车调用doRead()时数据在 Fesod 内部经历了一场接力赛。
这场比赛可以分为三个阶段。
第一阶段智能调度 (Dispatcher)谁在干活ExcelAnalyserImpl职责看人下菜碟路由选择。
核心逻辑Excel 有两种格式古老的.xls(BIFF
和现代的.xlsx(OOXML ZIP)。
ExcelAnalyserImpl不会盲目解析它会先偷看文件的前几个字节Magic Number或者尝试用 POI 的POIFSFileSystem去探测。
如果是.xls- 实例化XlsSaxAnalyser。
如果是.xlsx- 实例化XlsxSaxAnalyser。
如果是.csv- 实例化CsvExcelReadExecutor。
这就像老司机听一下发动机声音就知道该挂什么档。
第二阶段SAX 解析 (Parsing)谁在干活XlsxSaxAnalyser(继承自 DefaultHandler)职责把 XML 变成事件流。
核心逻辑这是最“硬核”的部分。
Excel 的.xlsx本质上是一堆 XML 文件的压缩包。
Fesod 直接利用 SAX 解析器去读sharedStrings.xml存字典和sheet
xml存数据。
它只关心三个事件StartElement(c rA
: 哟一个新的单元格来了记下它的坐标。
Characters(
: 读到了内容把它存到临时变量里。
EndElement(/row): 一行结束了赶紧把这行数据打包准备发货。
这种流式处理 (Streaming)意味着无论你的 Excel 有 100 万行还是 1000 万行Fesod 内存里永远只有“当前这一行”的数据。
第三阶段转换与回调 (Converting Callback)谁在干活Converter体系 和ReadListener职责把“生数据”变成“熟对象”。
核心逻辑SAX 读出来的都是 String。
但你的 Java Bean 里写的是Date、Double。
这时analysisContext里的转换器登场了。
它会自动匹配“这个格子是日期格式内容是 44567那我把它转成
。
”“这个格子是数字转成Double。
”转换完成后完整的 Java 对象被构建出来通过listener.invoke(data)回调给用户的代码。
用户处理完这行数据比如存库Fesod 就会擦除这行对象的引用等待 GC 回收。
时序图全景
技术高光状态的艺术AnalysisContext (背包客)在这个复杂的链条中如何保证状态不丢Fesod 设计了一个Context (上下文)对象。
它就像一个“背包”随着流程在各个节点间传递。
ReadSheetHolder背在包里当前解析的是哪个 SheetReadWorkbookHolder背在包里全局配置是什么AnalysisContextImpl甚至还维护了当前的行号。
这种设计让各个模块Analyser, Executor, Converter都变成了无状态的单例或者轻量级对象所有的状态都收敛在 Context 里。
这不仅线程安全而且极易扩展。
4.
总结Fesod 的读取架构是一次极其标准的事件驱动 (Event-Driven)实践。
它用Dispatcher屏蔽了底层差异。
它用SAX解决了内存瓶颈。
它用Context串联了复杂流程。
当你下一次看着控制台的日志一行行快速滚动且内存曲线平稳如直线时请记住这背后是无数个 XML 事件正在精密地起舞。