ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PlantUML Standard Library(stdlib)压缩格式与加载机制完全解析

PlantUML Standard Library(stdlib)压缩格式与加载机制完全解析 PlantUML Standard Librarystdlib压缩格式与加载机制完全解析【免费下载链接】plantumlGenerate diagrams from textual description项目地址: https://gitcode.com/gh_mirrors/pl/plantumlPlantUML 内置的标准库Standard Library即stdlib为开发者提供了 archimate、aws、azure、c4、kubernetes、material、logos、tupadr3 等大量开箱即用的图形资产与主题宏库。本文以仓库中的 stdlib 目录说明文档 为核心结合 Stdlib.java、SpmChannel.java 等源码与测试用例深入讲解 stdlib 的目录组织、.repx/.spm压缩存储格式、运行时加载链路、元数据协议以及相关的预处理、主题与精灵Sprite扩展点帮助读者彻底理解 PlantUML 内置库从打包到被!include解析的完整工作原理并掌握排查与扩展内置库的实战方法。一、stdlib 是什么在 PlantUML 中Standard Library 是一组随发行版一起内置的 PlantUML 宏与图形资产集合存放于仓库资源目录 src/main/resources/stdlib。它允许用户在绘图文本中直接引用形如!include aws/AWSCommon、!include c4/C4_Context的库文件而无需关心这些文件实际存放在哪里——因为它们并不以明文.puml形式存在于磁盘上而是被打包为压缩格式存储。仓库内 stdlib 的 README 明确说明了两点核心事实该目录存放的是**压缩格式.repx**的标准库文件标准库的明文源码另有独立的官方仓库维护plantuml/plantuml-stdlib以及一个协作式仓库plantuml-stdlib组织而压缩格式的解压与读取逻辑就在 net/sourceforge/plantuml/preproc/Stdlib.java 中。也就是说stdlib之于 PlantUML如同一个内置只读的宏仓库发布时把海量.puml源码压缩进一个个分卷文件运行时按需解压、惰性加载从而在保持丰富资产的同时显著缩小发行包体积。仓库中的目录实况查看 src/main/resources/stdlib 可以确认当前仓库内置了 30 余个标准库子目录例如架构类archimate、c4、cloudinsight、cloudogu、domainstory、edgy云厂商类aws、awslib、awslib10、awslib14、awslib20、azure、gcp、ibm容器与基础设施类k8s、kubernetes通用 UI/品牌类bootstrap、bootstrap1.12.1、bootstrap1.13.1、material、material2、material2.1.19、material7、material7.4.47、logos、office其他eip、elastic、classy、classy-c4、osa、osa2、tupadr3、adaml每个子目录下的文件均为一组.spm 对应.sha1的配对文件并随库的能力不同而增减通道文件例如子目录包含的通道文件.spm说明adamlinfo、puml仅元数据与宏源码c4info、puml、sprite额外含经典精灵awsinfo、puml、sprite精灵版本较早awslib20info、puml、sprite、svg、image、json通道最全bootstrap仅info仅有元数据的目录可能是别名或占位根目录还有一个特殊的home.spm它是一份纯文本清单逐行列出所有可用库名。从实际内容可以看到它按字母顺序列出了adaml、archimate、aws、awslib…… 直到tupadr3这正是 Stdlib.getAllFolderNames() 枚举所有内置库的依据。二、压缩格式与通道.spm 与 .repx解读2.1.repx与.spm的关系README 提到压缩格式为.repx而仓库实际存放的却是.spm文件。从 SpmChannel.java 的枚举定义可以看出SpmChannel定义了六个通道public enum SpmChannel { INFO, // PUML, // JSON, // SPRITE, // SVG, // IMAGE; }每个通道对应一个文件文件名的生成规则是name().toLowerCase().replace(_, -) .spm因此实际资源路径为stdlib/库名/通道名.spmpublic InputStream getInternalInputStream(String libname) throws IOException { final String path stdlib/ libname / getFileName(); return new BrotliInputStream(inputStream(path)); }关键结论通道文件通过Brotli 压缩算法BrotliInputStream存储打开时必须用 Brotli 解压.repx是压缩包在文档层面的统称/旧称.spm是当前仓库中实际落盘的通道文件后缀二者描述的是同一套分通道压缩的设计——可以推断.repx即 REPacked 一类打包产物的历史命名而.spm是通道打包文件Spm Channel Pack的具体实现资源既可以从 classpathStdlib.class.getResourceAsStream(/ path)读取也可以回退到文件系统new BufferedInputStream(new FileInputStream(path))这一回退逻辑见 SpmChannel.inputStream便于离线/本地化部署场景。2.2 各通道的二进制内容协议结合 Stdlib.java 的读取代码可以还原每个通道的二进制布局INFO 通道纯文本形如KEYVALUE的逐行键值对。构造函数按行读取并切分仅接受恰好两段的键值Stdlib 构造函数。标准键包括VERSION/version、SOURCE/source、LINK/link等。PUML 通道以DataInputStream顺序读取先是int表示条目总数随后循环读取每条UTF文件名、int数据长度、len字节的源码数据并以小写文件名作为 key 存入内存 MapinitMapIfNeeded。SPRITE 通道同样以条目数开头每条包含精灵名、宽度、高度以及width * ((height 1) / 2)字节的位图数据readSprite。SVG 通道条目数 每条名字, SVG 文本并通过SvgSpriteParserFactory.create(svg)直接构建可用的 SVG 精灵解析器readSvgSprite。IMAGE 通道先读取 2 字节表示的调色板大小再依次读取每个颜色项的 A/R/G/B 四字节随后每条图像包含宽、高与width * height * 2字节的索引色数据最终封装为FutureImagereadDataImagePng。这种按需分通道 惰性解压的设计意味着一个只画 C4 图、从不引用精灵的用户在运行时永远不会解压 SPRITE/SVG/IMAGE 通道的数据。2.3.sha1文件的作用每个.spm旁边都有一个同名.sha1文件。从命名与发布流程可以推断.sha1是通道压缩包的校验和文件用于在构建/发布/分发环节校验压缩包完整性防止打包产物损坏或内容被篡改。仓库中没有任何运行时逻辑读取.sha1因此它属于发布链路产物而非运行时依赖。三、运行时加载链路从!include到字节流当用户写下!include aws/AWSCommon时加载过程如何发生源码给出了完整链路预处理阶段识别 stdlib 引用PreprocessorUtils.getReaderStdlibInclude 负责处理 stdlib 形式的 include它调用Stdlib.getPumlResource(filename)若返回null则说明该库不存在否则把字节流交给DiagramDetector.extractFromBytes或ReadLineReader.create生成可供后续解析的行读取器。按库名检索Stdlib.getPumlResource 先把传入名转小写、去掉.puml后缀再以第一个/切分库名与文件路径库名 →retrieve(folderName)获取对应的Stdlib实例文件名 →folder.loadPumlResource(fileName)惰性解压 PUML 通道后取出对应字节。带缓存的实例化retrieve 使用ConcurrentHashMap.computeIfAbsent保证每个库名只解析一次构造函数会读取 INFO 通道若元数据中存在link键则会重定向到另一个库递归retrieve(link)——这是 stdlib 支持别名/软链的机制例如awslib可能通过link指向实际版本目录。并发安全的惰性解压loadPumlResource/loadJsonResource在synchronized块中调用initMapIfNeeded首次访问时才真正解压对应通道并建索引之后的访问全部走内存 Map兼顾线程安全与性能。除.puml宏外同类机制还服务于JSON 资源getJsonResource 解压 JSON 通道并以 UTF-8 解析为JsonValue供%load_json()等 TIM 内置函数使用主题加载ThemeUtils.loadStdlibTheme 通过Stdlib.getPumlResource加载形如!theme foo from stdlib/xxx的库内主题文件精灵命令CommandSpriteStdlib 与 CommandStdlib 支持sprite $name stdlib/库名/文件名之类的写法通过Stdlib.retrievereadSprite/readSvgSprite取得精灵数据。四、把 stdlib 当作虚拟文件系统除了预处理器的专用读取stdlib 还被设计为可挂载的只读虚拟目录。在 nio 包中存在NFolderStdlibNFolderStdlib.java它实现了NFolder接口public InputFile getInputFile(Path nameOrPath) throws IOException { return new InputFileStdlib(stdlib, pathInsideStdlib.resolve(nameOrPath).normalize()); } public NFolder getSubfolder(Path nameOrPath) throws IOException { return new NFolderStdlib(stdlib, pathInsideStdlib.resolve(nameOrPath).normalize()); }其toString()返回库名!子路径的表示形式意味着标准库可以被当作一个逻辑目录树参与 PlantUML 的路径解析体系——路径解析遇到 stdlib 前缀时会透明地把文件访问转化为从压缩通道按名取字节流。配套的InputFileStdlib负责把Path归一化后交给Stdlib.loadPumlResource。这解释了为什么!include既可以写库名/文件也可以在某些上下文按文件路径方式解析同时保持只读、无真实磁盘文件语义。五、元数据协议与%get_stdlib调试入口INFO 通道中的KEYVALUE键值对构成了 stdlib 的元数据协议通过 getMetadata()、getVersion()、getSource() 暴露。其中version/VERSION库版本号source/SOURCE库的来源/作者信息link库重定向目标见上文retrieve逻辑。这些元数据被 TIMTextual Integrated Modeling内置函数消费形成两个可直接在 PlantUML 脚本中使用的调试/信息入口GetStdlib.java 实现%get_stdlib()无参时返回全部库的元数据 JSON一个参数时返回指定库的元数据两个参数时返回指定库的指定键键先按小写匹配找不到再试大写找不到时返回空字符串。GetAllStdlib.java 实现%get_all_stdlib()无参返回全部库名及其元数据的 JSON 数组一个参数时按行列出库名 来源链接。对应的测试用例 GetAllStdlibTest.java 直接验证了这些行为无参调用结果必须包含archimate、aws、tupadr3等库名带参数调用结果必须包含 archimate 的来源地址https://github.com/plantuml-stdlib/Archimate-PlantUML。测试还提示一个细节README 中声明的元数据键在%get_stdlib中统一转为小写因此脚本中应优先使用小写键名。调试时可以直接在 PlantUML 脚本中写入startuml !function $show() !$j %get_stdlib(aws) !dump $j !endfunction enduml%get_stdlib(库名)返回 JSON 对象配合!dump可查看该库的元数据。六、版本信息与 CLI 中的呈现Stdlib.addInfoVersion 会把所有内置库的名称、版本与来源收集成列表printStdLib()则把这份列表输出到标准输出。从源码结构看这一能力会被版本/诊断页面PSystemVersion.java 引用了Stdlib用于在plantuml -version或诊断图中展示 stdlib 的汇总信息便于用户核对内置库版本是否符合预期。七、实战如何检查与排查 stdlib 问题基于以上原理总结几条可落地的排查/使用建议确认库是否存在查看 home.spm 的库名清单或运行plantuml -version观察列出的库版本若!include xxx/...报无法加载先确认库名是否在清单中、路径是否带上了.pumlgetPumlResource会自动去掉.puml后缀。区分宏、精灵与 SVG同名库的不同资产分散在不同通道。!include 库名/文件名走 PUML 通道sprite $name 库名/精灵名走 SPRITE/SVG 通道JSON 数据走 JSON 通道。排查精灵缺失时应确认该库是否包含sprite.spm/svg.spm文件如adaml、bootstrap目录就完全没有精灵通道。留意别名重定向若某个库名加载后内容与预期不符检查其info.spm中是否含有link键——retrieve会透明地跳转到目标库。只读性约束stdlib 在运行时是只读压缩资源无法直接向其中追加文件需要扩展内置资产时应回到 src/main/resources/stdlib 对应的明文源码仓库README 中给出的plantuml/plantuml-stdlib开发再经由构建流程重新打包为.spm通道文件。网络/本地回退SpmChannel.inputStream先查 classpath 再回退本地文件系统路径若部署环境中 classpath 缺失 stdlib 资源例如自定义精简分发可把stdlib/目录放置于工作目录下作为回退来源。八、总结PlantUML 的 Standard Library 远不止一堆现成的宏其背后是一套精密的分通道压缩存储 惰性加载 元数据协议 虚拟文件系统适配的工程实现资源以 Brotli 压缩的.spm通道文件存放info/puml/json/sprite/svg/imageREADME 中所称的.repx即这类压缩打包产物的统称核心加载逻辑集中在 Stdlib.java由 SpmChannel.java 提供通道寻址与解压预处理、主题、精灵、TIM 内置函数%get_stdlib/%get_all_stdlib等多处功能都复用了同一套Stdlib读取管线并以 GetAllStdlibTest.java 等测试保障行为稳定。理解这套机制后无论是排查!include加载失败、核对内置库版本还是规划如何向发行版扩充新的标准库资产都能做到有的放矢。附关键源码文件索引关注点文件stdlib 目录说明src/main/resources/stdlib/README.md核心加载类src/main/java/net/sourceforge/plantuml/preproc/Stdlib.java通道枚举与解压src/main/java/net/sourceforge/plantuml/preproc/spm/SpmChannel.java预处理 include 入口src/main/java/net/sourceforge/plantuml/preproc2/PreprocessorUtils.java虚拟目录适配src/main/java/net/sourceforge/plantuml/nio/NFolderStdlib.java元数据查询函数src/main/java/net/sourceforge/plantuml/tim/builtin/GetStdlib.java、src/main/java/net/sourceforge/plantuml/tim/builtin/GetAllStdlib.java主题/精灵复用src/main/java/net/sourceforge/plantuml/theme/ThemeUtils.java、src/main/java/net/sourceforge/plantuml/command/CommandSpriteStdlib.java行为验证测试src/test/java/net/sourceforge/plantuml/tim/builtin/GetAllStdlibTest.java【免费下载链接】plantumlGenerate diagrams from textual description项目地址: https://gitcode.com/gh_mirrors/pl/plantuml创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表