freemarker源码解读之一--概述

谁说我不能喝 提交于 2019-12-07 08:00:53

最近在思考为如何xsoup添加自定义函数支持,基于这个目的,想起了最常用的模板引擎freemarker。于是down了源码下来,开始浏览一番。本文基于https://github.com/freemarker/freemarker上的2.3.20版本。

思考

看源码前,先思考一下,一个模板引擎,到底需要哪些东西?一门模板引擎其实是一个完整的语言,只不过它只具有单纯的输入/输出,不需要考虑其他的功能。

  • 语法解析,转换为AST(抽象语法树)

  • 语义分析,为AST附加上执行语义

  • 上下文环境的注入

  • 内置函数及外部函数支持

  • 其他外围机制(与框架/工具的集成等)

源码结构

打开freemarker的代码,core包里110个类一字排开,还有以下划线开头的“建议不要看”的类,看的人眼花缭乱啊!这一切都是因为Java规范的大师们,设计了一个“包级可见“的概念,大概就是,我写给自己用的代码,不要让你用!这一来,别人用是用不了了,好像看起来也变得很困难了…

还好现在的IDE都很强大,刷刷两下就给重构了,把一些类按照类型挪到多个包里,顿时清爽很多!可惜好多类/方法/字段都是包级可见,为了让这个重构版freemarker没那么多红叉,lz加了好几百个public,写到意识都模糊了…最后把自己的劳动成果共享出来吧:https://github.com/code4craft/freemarker-learning。主要是将freemarker.core包里内容拆开了,语法树相关的内容放到了freemarker.core.nodes包,异常放到了freemarker.core.exception包,一些模板内置功能放到了freemarker.core.buildin包,还有工具类放到了freemarker.core.util包。

顺便将freemarker的流程整理了一下:

流程

这是一个很经典的模板引擎的执行流程:

  • Configuration可以理解为一个工厂,它负责产生一个对外接口Template类。它首先会从cache中查找是否已经有编译好的Template,如果不存在,则对模板进行编译。
  • Template实际上是一个带执行语义的语法树,树的节点是TemplateObject。
  • FMParser是javacc生成的语法解析类,它最终输出是以FMParser.root()为根的语法树。
  • dataModel是外部对模板引擎的数据输入,它会被转化为TemplateModel,并代入模板的渲染过程。
  • 最后的步骤是根据数据,遍历编译好的语法树,并输出结果,这一步的入口时TemplateElement.accept()。

关于JavaCC

freemarker使用了JavaCC(Java Compiler Compiler)做parser。关于JavaCC,有一篇很好的入门帖,顺带复习一下编译原理:LL(0)文法,消除左递归等东西。http://cs.lmu.edu/~ray/notes/javacc/

JavaCC的下载在这里:http://javacc.java.net/,不知是我操作失误还是怎样,下载JavaCC-6.0之后,bin目录只有lib/javacc.jar文件。下载JavaCC-5.0src之后,才找到javacc脚本。难道就这么几百K的东西,还要搞增量更新?

总之下载成功之后,用javacc FTL.jj,即可生成一堆Parser文件。核心是FMParser,解析完的语法树在FMParser.root()里。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!