模版加载

 
  • 模版加载器

 

当调用 cfg.getTemplate(这里的 cfg 就是Configuration 实例)时,FreeMarker 询 问模板加载器是否已经为 cfg 建立返回给定模板路径的文本,之后 FreeMarker 解析文本生 成模板。

 

  • 内建模版加载器

 

在 Configuration 中可以使用下面的方法来方便建立三种模板加载。(每种方法都 会在其内部新建一个模板加载器对象,然后创建 Configuration 实例来使用它。)

 

void setDirectoryForTemplateLoading(File dir);

void setClassForTemplateLoading(Class cl, String prefix); 

 或

void setServletContextForTemplateLoading(Object servletContext, String path); 

 

上述的第一种方法在磁盘的文件系统上设置了一个明确的目录,它确定了从哪里加载模板。不要说可能,File 参数肯定是一个存在的目录。否则,将会抛出异常。 

第二种调用方法使用了一个 Class 类型的参数和一个前缀。这是让你来指定什么时候通过相同的机制来加载模板,不过是用 Java 的 ClassLoader 来加载类。这就意味着传入的 Class参数会被用来调用Class.getResource()方法来找到模板。参数prefix 是给模板的名称来加前缀的。在实际运行的环境中,类加载机制是首选用来加载模板的方法, 因为通常情况下,从类路径下加载文件的这种机制,要比从文件系统的特定目录位置加载安全而且简单。在最终的应用程序中,所有代码都使用.jar 文件打包也是不错的,这样用户就可以直接执行包含所有资源的.jar 文件了。 

第三种调用方式需要 Web 应用的上下文和一个基路径作为参数,这个基路径是 Web 应 用根路径(WEB-INF 目录的上级目录)的相对路径。那么加载器将会从 Web 应用目录开 始加载模板。尽管加载方法对没有打包的.war 文 件 起 作用 , 因 为 它 使 用 了 ServletContext.getResource()方法来访问模板,注意这里我们指的是“目录” 。 如果忽略了第二个参数(或使用了””),那么就可以混合存储静态文件(.html,.jpg 等) 和.ftl 文件,只是.ftl 文件可以被送到客户端执行。当然必须在WEB-INF/web.xml 中配置一个 Servlet 来处理 URI 格式为*.ftl 的用户请求,否则客户端无法获取到模板,因 此你将会看到 Web 服务器给出的秘密提示内容。在站点中不能使用空路径,这将成为一个 问题,你应该在 WEB-INF 目录下的某个位置存储模板文件,这样模板源文件就不会偶然
void setDirectoryForTemplateLoading(File dir);
void setClassForTemplateLoading(Class cl, String prefix);
void setServletContextForTemplateLoading(Object servletContext, String path);
地被执行到,这种机制对 servlet 应用程序来加载模板来说,是非常好用的方式,而且模板 可以自动更新而不需重启 Web 应用程序,但是对于类加载机制,这样就行不通了。

 

  • 从多个位置加载模板

 

如果需要从多个位置加载模板,那就不得不为每个位置都实例化模板加载器对象,将它 们包装到一个被成为 MultiTemplateLoader 的特殊模板加载器,最终将这个加载器 传递给 Configuration 对象的 setTemplateLoader(TemplateLoader loader)方法。下面给出一个使用类加载器从两个不同位置加载模板的示例:  

 

 

import freemarker.cache.*; // 模板加载器在这个包下 ... 
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 目录下加载,如果 还是没有发现请求的模板,那么它就会使用类加载器来加载模板。

 

  • 从其他资源加载模板

如果内建的类加载器都不适合使用,那么就需要来编写自己的类加载器了,这个类需要 实现 freemarker.cache.TemplateLoader 接口,然后将它传递给 Configuration 对象的 setTemplateLoader(TemplateLoader loader) 方法。可以阅读 FreeMarker API 文档获取更多信息。  如果你的模板需要通过 URL 访问其他模板,那么就不需要实现 TemplateLoader 接口了,可以选择子接口 freemarker.cache.URLTemplateLoader 来替代,只 需实现 URL getURL(String templateName)方法即可。

 

  • 模板路径

解析模板的路径是由模板解析器来决定的。但是要和其它对路径的格式要求很严格的组 件一起工作。通常来说,强烈建议模板加载器使用 URL 风格的路径。在 URL 路径(或在 UN*X 路径)中有其它含义时,那么路径中不要使用/,./,../和:// 。字符*和?是被保留的。 而且,模板加载器也不想模板以/开始;FreeMarker 从来不会使用这样的路径来调用模板加
import freemarker.cache.*; // 模板加载器在这个包下 ... 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 再将路径传递给模板加载器之前通常会将路径进行正常化操作,所以相对 于假想的模板根目录,路径中不会含有/../这些东西。 注意 FreeMarker 模板加载时经常使用斜线(而不是反斜线),不管运行的主机操作系统 是什么。

 

  • 模板缓存

FreeMarker 是会缓存模板的(假设使用 Configuration 对象的方法来创建 Template 对象)。这就是说当调用 getTemplate 方法时,FreeMarker 不但返回了 Template 对象的结果,而且还会将它存储在缓存中,当下一次再以相同(或相等)路径 调用 getTemplate 方法时,那么它只返回缓存的 Template 实例,而不会再次加载 和解析模板文件了。

如果更改了模板文件,当下次调用模板时,FreeMarker 将会自动重新载入和解析模板。 然而,要检查模板文件是否改变内容了是需要时间的,有一个 Configuration 级别的 设置被称作为“更新延迟”可以用来配置这个时间。这个时间就是从上次对某个模板检查更 新后,FreeMarker 再次检查模板所要间隔的时间。其默认值是 5 秒。如果想要看到模板立即 更新的效果,那么就要把它设置为 0。要注意某些模板加载器也许在模板更新时可能会有问 题。例如,典型的例子就是在基于类加载器的模板加载器就不会注意到模板文件内容的改变。

当调用了 getTemplate 方法时,与此同时 FreeMarker 意识到这个模板文件已经被 移除了,所以这个模板也会从缓存中移除。如果 Java 虚拟机认为会有内存溢出时,默认情 况它会将任意的模板从缓存中移除。此外,你还可以使用 Configuration 对象的 clearTemplateCache 方法手动清空缓存。

何时将一个被缓存了的模板清除的实际应用策略是由配置的属性 cache_storage 来确定的,通过这个属性可以配置任何 CacheStorage 的实现。对于大多数用户来说, 使用 freemarker.cache.MruCacheStorage 就足够了。这个缓存存储实现了二 级最近使用的缓存。在第一级缓存中,组件都被强烈引用到特定的最大数目(引用次数最多 的组件不会被 Java 虚拟机抛弃,而引用次数很少的组件则相反)。当超过最大数量时,最近 最少使用的组件将被送至二级缓存中,在那里它们被很少引用,直到达到另一个最大的数目。 引用强度的大小可以由构造方法来指定。例如,设置强烈部分为 20,轻微部分为 250:

cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250)) 

或者,使用 MruCacheStorage 缓存,它是默认的缓存存储实现。

cfg.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:20, soft:250"); 

 当创建了一个新的 Configuration 对象时,它使用一个 maxStrongSize 值为 0 的 MruCacheStorage 缓存来 初 始 化 , maxSoftSize 的值是 Integer.MAX_VALUE(也就是说在实际中, 是无限大 的)。但是使用 非 0 的 maxStrongSize 对于高负载的服务器来说也许是一个更好的策略,对于少量引用的组 件来说,如果资源消耗已经很高的话,Java 虚拟机往往会引发更高的资源消耗,因为它不断 从缓存中抛出经常使用的模板,这些模板还不得不再次加载和解析。

 

你可能感兴趣的:(加载)