Skip to content

模板解析器链

Thymeleaf 的模板引擎(Template Engine)支持配置多个模板解析器,并可为它们设定优先级顺序——解析模板时,会先尝试第一个解析器,若它无法解析该模板,再依次尝试第二个、第三个,以此类推:

java
// 1. 类加载器模板解析器,优先级设为 1(优先尝试)
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));

// 2. Web应用模板解析器,优先级设为 2(第一个解析失败时尝试)
WebApplicationTemplateResolver webApplicationTemplateResolver = 
        new WebApplicationTemplateResolver(application);
webApplicationTemplateResolver.setOrder(Integer.valueOf(2));

// 将两个解析器添加到模板引擎,按 order 顺序生效
templateEngine.addTemplateResolver(classLoaderTemplateResolver);
templateEngine.addTemplateResolver(webApplicationTemplateResolver);

配置多解析器时,建议为每个解析器指定模板路径匹配规则,这样 Thymeleaf 能快速跳过不匹配的解析器,提升性能(非强制要求,但强烈推荐):

java
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));
// 仅解析 /layout/*.html 和 /menu/*.html 路径的模板,其他路径直接跳过
classLoaderTemplateResolver.getResolvablePatternSpec().addPattern("/layout/*.html");
classLoaderTemplateResolver.getResolvablePatternSpec().addPattern("/menu/*.html");

WebApplicationTemplateResolver webApplicationTemplateResolver = 
        new WebApplicationTemplateResolver(application);
webApplicationTemplateResolver.setOrder(Integer.valueOf(2));

如果未指定可解析路径,模板解析器的行为依赖于 ITemplateResolver 实现类的具体逻辑——部分实现类无法在解析前判断模板是否存在,可能会「误判模板可解析」,从而中断解析链(不让后续解析器尝试),但最终又无法读取到实际资源。

为解决这个问题,Thymeleaf 核心包提供的所有 ITemplateResolver 实现类都支持 checkExistence 标志,强制解析器在解析阶段先检查资源是否存在:

java
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));
// 开启存在性检查:解析前先确认模板资源存在,不存在则交给下一个解析器
classLoaderTemplateResolver.setCheckExistence(true);
checkExistence 的利弊
  • 优势:确保解析链正常执行——只有当当前解析器确认资源存在时,才会处理模板;不存在则交给下一个解析器,避免解析链被错误中断。
  • 劣势:可能导致资源双重访问(第一次检查存在性,第二次读取内容),在某些场景下(如基于远程 URL 的模板资源)会有性能损耗;不过这种损耗可通过模板缓存大幅缓解(模板仅在第一次访问时解析,后续直接使用缓存)。

核心解析

1. 解析器链的执行逻辑

  • setOrder() 设定的数字从小到大执行(数字越小,优先级越高);
  • 若某解析器「能解析并找到模板」,则直接使用该解析器,终止解析链;
  • 若某解析器「无法解析/找不到模板」,则继续尝试下一个解析器;
  • 若所有解析器都失败,则抛出模板未找到异常。

2. 可解析路径的价值

  • 避免无效尝试:比如类加载器解析器只负责 /layout/ 路径的模板,当解析 /order/detail.html 时,会直接跳过该解析器,无需执行后续的存在性检查,提升性能;
  • 明确职责划分:不同解析器负责不同路径的模板,便于维护(如通用布局模板用类加载器解析,业务模板用 Web 应用解析器)。

3. checkExistence 的使用场景

  • 推荐开启:当解析器处理的是本地文件、类路径资源(访问成本低),或解析链中存在多个解析器时,开启后能保证解析逻辑的正确性;
  • 谨慎开启:当解析器处理的是远程 URL、网络资源(访问成本高),且已通过 resolvablePatterns 严格限定路径时,可关闭以避免双重访问的性能损耗。

总结

  1. 模板引擎支持配置多个解析器并通过 setOrder() 设定优先级,形成解析链;
  2. 为解析器指定 resolvablePatterns 可跳过无效解析尝试,提升性能,是最佳实践;
  3. checkExistence=true 可强制解析器先检查资源存在性,保证解析链正常执行,但可能导致资源双重访问,需结合缓存和资源类型权衡使用;
  4. 解析器链的核心价值:实现不同路径/类型的模板由不同解析器处理,提升模板加载的灵活性和可维护性。