3

Beetl 源码解析:GroupTemplate 类 - 腐烂的橘子

 1 week ago
source link: https://www.cnblogs.com/rottenorange-cn/p/18153101
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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<Listener> ls = new ArrayList<Listener>(); // 所有注册的方法 Map<String, Function> fnMap = new HashMap<String, Function>(); // 格式化函数 Map<String, Format> formatMap = new HashMap<String, Format>(); Map<Class, Format> defaultFormatMap = new HashMap<Class, Format>(0); // 虚拟函数 List<VirtualAttributeEval> virtualAttributeList = new ArrayList<VirtualAttributeEval>(); Map<Class, VirtualClassAttribute> virtualClass = new HashMap<Class, VirtualClassAttribute>(); // 标签函数 Map<String, TagFactory> tagFactoryMap = new HashMap<String, TagFactory>(); ClassSearch classSearch = null; // java调用安全管理器 NativeSecurityManager nativeSecurity = null; ErrorHandler errorHandler = null; Map<String, Object> 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. 初始化自定义方法,即 beetl.properties 中配置的方法
  3. 初始化拓展资源,包括 formatMapdefaultFormatmap
  4. 初始化 tag,即配置里的 tagFactoryMap
  5. 初始化虚拟函数
  6. 初始化缓冲区

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 构建暴露特定方法的自定义缓存管理器。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK