Beetl 源码解析:GroupTemplate 类

本文首发于公众号:腐烂的橘子

前言

Beetl 是一款 Java 模板引擎,在公司的项目中大量运用,它的作用是写通用代码时,有一些差异化的逻辑需要处理,这时可以把这些差异化的逻辑写在模板里,程序直接调用,实现了代码的低耦合。

有人问差异化的东西为什么不能通过配置实现?原因是配置只能将一些差异化的值抽离出来,一些复杂的逻辑很难做到。比如有一个类似计算器的界面,里面可以对一些业务字段进行公式计算:

  • 分润 = 利息 * 0.2
  • 分润 = (利息 + 罚息) * 0.1

程序在计算这个表达式前,并不知道表达式的具体内容,只是想由业务传入利息、罚息这些字段上下文信息后,能自动计算出结果。这时使用 Beetl 模板,我们将上面的公式用 Beetl 表达式表示:

  • <%print(interest * 0.2);%>
  • <%print((interest + penalty) * 0.2);%>

代码中就不用感知具体公式内容了,直接写通用逻辑即可:



|  | public static void main(String[] args) throws IOException { |
|  | // 用户输入的公式 |
|  | String formula = "xxxx"; |
|  | // 计算结果的上下文参数 |
|  | HashMap param = new HashMap(); |
|  | // 核心代码 |
|  | GroupTemplate gt = new GroupTemplate(new StringTemplateResourceLoader(), Configuration.defaultConfiguration();); |
|  | Template template = gt.getTemplate(formula); |
|  |  template.binding(new HashMap()); |
|  | // ans 就是计算的结果 |
|  | String ans = template.render(); |
|  | } |


以上就是 Beetl 的基本使用方法,具体可以参考文档,接下来的几篇文章,将对其源码进行解析,如有不合理的地方,欢迎各位大佬批评指正。

核心类 GroupTemplate 源码解析

核心字段定义

GroupTemplate 类核心字段定义如下:



|  | public class GroupTemplate { |
|  |  |
|  | /* 模板在运行过程中,class方法,accessory调用等需要的classLoader */ |
|  | ClassLoader classLoader = Thread.currentThread().getContextClassLoader() != null |
|  |  ? Thread.currentThread().getContextClassLoader() |
|  |  : GroupTemplate.class.getClassLoader(); |
|  |  |
|  |  |
|  | AABuilder attributeAccessFactory = new AABuilder(); |
|  | ResourceLoader resourceLoader = null; |
|  | Configuration conf = null; |
|  | TemplateEngine engine = null; |
|  | Cache programCache = ProgramCacheFactory.defaulCache(); |
|  |  List ls = new ArrayList(); |
|  | // 所有注册的方法 |
|  |  Map fnMap = new HashMap(); |
|  | // 格式化函数 |
|  |  Map formatMap = new HashMap(); |
|  |  Map defaultFormatMap = new HashMap(0); |
|  | // 虚拟函数 |
|  |  List virtualAttributeList = new ArrayList(); |
|  |  Map virtualClass = new HashMap(); |
|  | // 标签函数 |
|  |  Map tagFactoryMap = new HashMap(); |
|  | ClassSearch classSearch = null; |
|  | // java调用安全管理器 |
|  | NativeSecurityManager nativeSecurity = null; |
|  | ErrorHandler errorHandler = null; |
|  |  Map sharedVars = null; |
|  |  |
|  | ContextLocalBuffers buffers = null; |
|  |  |
|  | // 用于解析html tag得属性,转化为符合js变量名字 |
|  | AttributeNameConvert htmlTagAttrNameConvert = null; |
|  |  |
|  | //... |
|  | } |


核心字段解释如下:

  • classLoader: 模板在运行中需要的 ClassLoader
  • attributeAccessFactory: 一个工厂类,为一个特定类的方法生成 AttributeAccess,如果类是 Map,则生成 MapAA;如果类是 List, 则生成 ListAA 等
  • resourceLoader: 资源加载器,根据 GroupTemplate 的 key 获取对应资源的加载器,可以是文件、字符串等
  • conf: 模板配置,核心类,与 Beetl 相关的所有配置
  • engine: 模板引擎,只有一个 createProgram 方法,这个方法可以生成一个用来执行模板的程序
  • programCache: 本地缓存,基于 ConcurrentHashMap 实现
  • ls: 事件的监听器列表,暂时没用

GroupTemplate 核心方法

构造方法

构造方法主要分为三步:

  1. 初始化默认配置
  2. 执行 init() 初始化方法,后面会讲
  3. 初始化资源加载器,实际上就是初始化 resourceLoader


|  | public GroupTemplate() { |
|  | try { |
|  | this.conf = Configuration.defaultConfiguration(); |
|  |  init(); |
|  |  initResourceLoader(); |
|  |  } catch (Exception ex) { |
|  | throw new RuntimeException("初始化失败", ex); |
|  |  } |
|  | } |


init() 方法内部包含很多初始化行为,具体包括:

  1. 构建配置
  2. 初始化模板引擎
  3. 初始化自定义方法,即 beetl.properties 中配置的方法
  4. 初始化拓展资源,包括 formatMapdefaultFormatmap
  5. 初始化 tag,即配置里的 tagFactoryMap
  6. 初始化虚拟函数
  7. 初始化缓冲区

init() 方法



|  | protected void init() { |
|  |  conf.build(); |
|  |  engine = TemplateEngineFactory.getEngine(conf.getEngine()); |
|  | this.initFunction(); |
|  | this.initFormatter(); |
|  | this.initTag(); |
|  | this.initVirtual(); |
|  | this.initBuffers(); |
|  |  |
|  |  classSearch = new ClassSearch(conf.getPkgList(), this); |
|  |  nativeSecurity = (NativeSecurityManager) ObjectUtil.instance(conf.getNativeSecurity(), this.classLoader); |
|  | if (conf.errorHandlerClass == null) { |
|  |  errorHandler = null; |
|  |  } else { |
|  |  errorHandler = (ErrorHandler) ObjectUtil.instance(conf.errorHandlerClass, classLoader); |
|  |  |
|  |  } |
|  |  |
|  |  htmlTagAttrNameConvert = (AttributeNameConvert)ObjectUtil.instance(conf.htmlTagAttributeConvert, classLoader); |
|  | } |


总结

GroupTemplate 是 Beetl 模板的核心类,我们看到这个类非常重,里面包含了大量属性,这些属性都为后续模板计算提供相关资源。类中的大部分属性都使用了 HashMap 来存放上下文信息,这为我们设计一些类时提供了一定参考。其中缓存管理比较简单,基本就是封装了 ConcurrentHashMap 的方法,只对外暴露 4 个方法,这也是我们构建本地缓存管理的常用方式:基于 ConcurrentHashMap 构建暴露特定方法的自定义缓存管理器。

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值