Configuration 是一个存放应用级别(application level)公共配置信息,以及模版(Template)可以使用的全局共享变量的一个对象。同时它还负责模版(Template)实例的建立以及缓存。Configuration 其实是freemarker.template.Configuration 对象的实例,使用其构造函数建立。一般应用使用一个共享的单实例Configuration 对象。 java
Configuration 对象可被Template 对象的方法使用,每个模版实例都关联与一个Configuration 实例,它是经过Template 的构造函数被关联进去的,一般是你使用这个方法来Configuration.getTemplate 得到模版对象的。 web
共享变量是那些定义给全部模版(Template)使用的变量。你能够经过configuration对象的setSharedVariable 方法来添加共享变量。 缓存
Configuration cfg = new Configuration(); ... cfg.setSharedVariable("wrap", new WrapDirective()); cfg.setSharedVariable("company", "Foo Inc."); // Using ObjectWrapper.DEFAULT_WRAPPER
全部与该configuration 对象关联的模版实例都就能够经过得到to_upper 转换器,company 来得到字符串,所以你不须要再一次次的往root 中添加这些变量了。若是你往root 添加同名的变量,那么你新添加的变量将会覆盖以前的共享变量。 安全
警告! 多线程
若是configuration 对象被多线程调用,那么不要使用TemplateModel 实现类做为共享变量,由于他们是非线程安全的,例如基于servlet 的web 站点就是这种状况。 app
Configuration 对象初始化时已经包含一些共享转换器变量: ide
名字类 函数
name | class |
---|---|
capture_output | freemarker.template.utility.CaptureOutput |
compress | freemarker.template.utility.StandardCompress |
html_escape | freemarker.template.utility.HtmlEscape |
normalize_newlines | freemarker.template.utility.NormalizeNewlines |
xml_escape | freemarker.template.utility.XmlEscape |
配置参数是那些能够影响FreeMarker 运行行为的那些命名参数。例如locale,number_format。
配置参数存储在Configuration实例中,它能够被模版实例(Template)修改。例如,你在Configuration中设置了locale等于"en_US",那么全部的模版对象都会使用,"en_US"除非你在单个模版实例中利用setLocale方法修改了默认配置。所以configuration设置的参数能够看成是默认参数,它能够被Template一级设置的参数覆盖,而它们二者设置的参数信息又能够被环境中设置的参数所覆盖(也就是模版文件指令设置的)以下:
${1.2} <#setting locale="en_US"> ${1.2}
这种调用方式你能够想象成3 个层(配置对象层,模版层,运行环境层)下面表格中显示了每一层对于参数的设置:
Setting A | Setting B | Setting C | Setting D | Setting E | Setting F | |
---|---|---|---|---|---|---|
Layer 3:Environment | 1 | - | - | 1 | - | - |
Layer 2:Template | 2 | 2 | - | - | 2 | - |
Layer 1:Configuration | 3 | 3 | 3 | 3 | - | - |
那么配置参数的最终结果分别是:A = 1, B = 2, C = 3, D = 1, E = 2.而F 参数极可能就是null。
若是要查询可设置的参数列表,你能够查阅FreeMarker API 文档的如下两个部分:
全部层的配置
freemarker.core.Configurable.setSetting(String, String)
Coniguration 层的配置
freemarker.template.Configuration.setSetting(String,String)
模版加载器
模版加载器是基于抽象路径("index.ftl"或"products/catalog.ftl")加载原始数据的那些对象,而究竟加载何种资源(目录中的文件数据仍是数据库中的数据)取决于具体的加载器实现。当你调用cfg.getTemplate 时,FreeMarker 将会询问你以前配置给Configuration 对象的模版加载器,有该模版加载器负责文件的载入。
内建的模版加载器
你能够用如下三个方法来设置模版加载的三种方式
void setDirectoryForTemplateLoading(File dir);
或者
void setClassForTemplateLoading(Class cl, String prefix);
或者
void setServletContextForTemplateLoading(Object servletContext, String path);
以上第一种方式显示的指定了一个文件系统中的目录,FreeMarker 将会在此目录记载模版,不用说,此目录必须存在,否在会抛出异常。
第二种方式以一个Class做为一个输入参数,当你想使用ClassLoader的方式来加载模版的时候,你就可使用这种方式,这种方式将会调用来寻找模版文件,同时这种模版加载的方式要比前一种稳定一些尤为是在生产系统中。你能够很容易的把资源文件,以及图标等打包到.jar 文件中。
第三种方式把web 应用的上下文以及基路径(相对与WEN-INF 的父路进来讲)做为参数。该种方式的模版加载器将会从web 应用上下文种加载模版。
从多个位置加载模版
若是你想从多个位置加载模版的话,你能够分别建立与不一样位置对应的单个模版加载器,而后把它们包裹到一个名叫MultiTemplateLoader模版加载器中,最终经过方法setTemplateLoader(TemplateLoader loader)把其设置给Configuration 对象,如下有一个从两个不一样位置加载模版的例子:
import freemarker.cache.*; // template loaders live in this package ... FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates")); FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates")); ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), ""); TemplateLoader[] loaders = new TemplateLoader[] { ftl1, ftl2, ctl }; MultiTemplateLoader mtl = new MultiTemplateLoader(loaders); cfg.setTemplateLoader(mtl);
FreeMarker 将会首先在路径/tmp/templates中搜索模版文件,若是没有找到那么回到路径/usr/data/templates中搜索,若是尚未找到,那么则会尝试用class-loader的方式加载。
从其余资源中获取模版文件
若是在这些内建的模版加载器中没有一个符合你的要求,那么你能够本身定制一个模版加载器,只须要实现freemarker.cache.TemplateLoader 接口就能够了,而后经过方法setTemplateLoader(TemplateLoader loader)把其传递给Configuration对象。
缓存模版
FreeMarker缓存模版的意思就是,当你经过getTemplate方法获取一个模版的时候,FreeMarker不只会返回一个Template对象,并且会缓存该对象,当你下一次以相同的路径请求模版的时候,它就会返回缓存中的模版对象。若是你改变了模版文件,那么当你下一次获取模版的时候,FreeMarker会自动从新加载,从新解析模版。虽然如此,可是若是直接判断一个文件是否修改过是一个耗时的操做,那么FreeMarker 在Configuration 对象级别提供了一个配置参数“update delay”。该参数的意思是FreeMarker多长时间去判断一次模版的版本,默认设置是5秒钟,也就是每一个5秒就会判断模版是否通过修改,若是你想实时的判断,那么设置该参数为0。另一点须要注意,并非全部的加载器都支持这种判断方式,举例来讲基于class-loader 的模版加载器就不会发现你修改过模版文件。
对于删除缓存中的模版FreeMarker 是这么作的,你可使用Configuration 对象方法clearTemplateCache 以手工的方式清楚缓存中的模版对象。而实际上缓存部分能够做为一个组建加入到FreeMarker 中(也就是它可使用第三方缓存方案)你能够经过设置cache_storage 这个参数来实现。对大多数开发者来FreeMarker 自带的freemarker.cache.MruCacheStorage 实现已经足够了。这个缓存使用2 个级别的Most Recently Used(最近最多用)策略。在第一个级别,全部的缓存条目都是使用强引用(strongly referenced:条目并不会被JVM 所清楚,与其相对的弱引用softly reference)直到达到最大时间,那些最近最少使用的条目就会被迁移到二级缓存。在这个级别条目都是使用弱引用直到达到过时。若引用与强引用的区域的大小是能够在构造函数中设置的,例如你想把强引用区域设置为20,弱引用区域设置为250,那你可使用如下代码:
cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))
因为MruCacheStorage 是默认的缓存实现,那么你也能够这样设置:
cfg.setSetting(Configuration.CACHE_STORAGE_KEY,"strong:20, soft:250");
当你建立一个新的Configuration时,其默认使用MruCacheStorage缓存实现且默认的值maxStrongSize等于0,maxSoftSize等于Integer.MAX_VALUE(也就是理论最大值)。可是对于高负荷的系统来讲,咱们建议maxStrongSize 设置成一个非0 的数值,否则会致使频繁的从新加载,从新解析模版。
可能产生的异常
FreeMarker 产生的异常通常可归如下几类:
FreeMarker 初始化阶段产生的异常: 一般在你的应用中仅须要初始化FreeMarker 一次,而当在这个时间段类产生的异常就叫作初始化异常。
加载解析模版期的异常:当你经过Configuration.getTemplate()方法获取模版的时候(若是模版以前没有被缓存),将会产生两类异常:
执行期间的异常:当你调用Template.process(...)方法的时候,会抛出两类异常:
原文由motomagice@yahoo.com.cn翻译自FreeMarker官方手册《Programmer's Guide》。