freemarker源码解读之一--概述
2015-09-08 17:44
323 查看
最近在思考为如何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()。
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()里。
思考
看源码前,先思考一下,一个模板引擎,到底需要哪些东西?一门模板引擎其实是一个完整的语言,只不过它只具有单纯的输入/输出,不需要考虑其他的功能。语法解析,转换为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()里。
相关文章推荐
- Populating Next Right Pointers in Each Node II
- 发布一个参考ssdb,使用go类似的实现redis高性能nosql:ledisdb
- 文本框 只能输入数字和小数点验证
- ThinkPHP函数详解:D方法
- 【攻克Android (41)】HttpURLConnection
- 通用权限管理设计 之 数据库结构设计
- CentOS 7 关闭防火墙 SELinux , FireWalld
- 别小看文章的网址,里面暗藏玄机
- 在CentOS 6.3 64bit上搭建python高性能框架gevent开发环境
- MYSQL存储过程和存储函数入门
- ThinkPHP框架使用Smarty模板引擎
- 【Android Studio简易教程】断点调试及相关技巧
- com.alibaba.dubbo.remoting.RemotingException:
- Storm系列(四)Topology提交校验过程
- SRBF Lighting
- [AngularJS + Webpack] Requiring Templates
- iOS UITabBarController按钮凸起效果实现
- 只让页面刷新一次.用js来实现
- jvm gc 原理测试
- Asp.net MVC 与 Asp.net Web API 区别