Skip to content

6.3 通过延迟加载数据优化性能

在实际开发中,我们有时希望优化数据集合的获取逻辑(比如从数据库查询数据)——只有当这些集合确实要被使用时,才执行获取操作

INFO

这种优化思路其实适用于任意类型的数据,但考虑到内存中集合可能占用较大空间,“延迟加载待遍历的集合”是最常见的应用场景。

要实现延迟加载,需让上下文变量实现 ILazyContextVariable 接口(通常继承其默认实现类 LazyContextVariable),数据的实际加载逻辑写在 loadValue() 方法中——这个方法仅在模板首次使用该变量时才会执行

java
// 将 "users" 变量设为延迟加载,仅在模板使用时才执行数据库查询
context.setVariable(
     "users",
     new LazyContextVariable<List<User>>() {
         @Override
         protected List<User> loadValue() {
             // 实际的数据获取逻辑(如数据库查询)
             return databaseRepository.findAllUsers();
         }
     });

延迟加载的变量在模板中使用时,无需感知其“延迟”特性,用法和普通变量完全一致:

html
<!-- 正常遍历延迟加载的 users 集合 -->
<ul>
  <li th:each="u : ${users}" th:text="${u.name}">user name</li>
</ul>

如果变量被 th:if 等条件包裹,且条件为 false,则 loadValue() 方法永远不会执行,数据库查询也不会触发:

html
<!-- 当 ${condition} 为 false 时,<ul> 不会渲染,users 的 loadValue() 也不会执行 -->
<ul th:if="${condition}">
  <li th:each="u : ${users}" th:text="${u.name}">user name</li>
</ul>

关键说明

  • 透明使用:模板端无需修改任何代码,延迟加载对模板是完全透明的;
  • 执行时机loadValue() 仅在变量首次被模板访问时执行一次,后续访问会复用已加载的数据;
  • 适用场景
    • 数据查询成本高(如复杂数据库查询、远程接口调用);
    • 变量的使用依赖条件判断(如仅在特定权限/场景下显示数据);
    • 集合数据量大,避免不必要的内存占用。

扩展示例(Spring 集成场景)

在 Spring + Thymeleaf 项目中,也可结合 Spring 的懒加载特性简化写法:

java
// Spring 环境下更简洁的写法(借助 Lambda)
context.setVariable("products", (LazyContextVariable<List<Product>>) () -> 
    productRepository.findAll()
);

总结

  1. Thymeleaf 的延迟加载变量(LazyContextVariable)能让数据仅在模板实际使用时才执行加载逻辑,避免无效的数据库/远程调用;
  2. 实现方式是继承 LazyContextVariable 并重写 loadValue(),模板端使用方式与普通变量完全一致;
  3. 核心价值:在变量使用受条件控制时,避免不必要的性能损耗,尤其适合大数据集合、高成本查询的场景。