You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot中Thymeleaf间歇性抛出模板异常求助

问题根源与解决方案

这个间歇性出现的错误,根源是Spring SpEL编译器的已知bug——你使用的Spring Boot 2.1.0.RELEASE对应Spring 5.1.x版本,当通过反向顺序的索引访问集合时,SpEL编译器会生成有问题的字节码,最终触发java.lang.VerifyError

为什么是间歇性的?因为SpEL编译器默认是懒加载触发:当同一个表达式执行次数超过阈值(默认100次)时,才会尝试将表达式编译为字节码以提升性能。所以只有当这个页面被访问足够多次后才会触发错误,重启服务器后编译状态重置,初期不会出错,直到再次达到编译阈值才会复现问题。


解决方案(按推荐优先级排序)

1. 升级Spring Boot版本(最优解)

这个SpEL编译器的bug在Spring 5.1.10+版本中已被修复,对应Spring Boot 2.1.10.RELEASE及以上版本。建议直接升级到稳定的新版本,比如:

  • 2.1.x系列的最后一个稳定版:2.1.18.RELEASE
  • 或者更高的长期支持版本(如2.3.x、2.7.x)

升级后既能从根源解决问题,还能获得其他bug修复和性能提升。

2. 禁用SpEL编译器(快速临时修复)

如果暂时无法升级,可以直接关闭SpEL的编译功能,避免生成错误的字节码。在application.properties中添加以下配置:

spring.expression.compiler.mode=off

这个配置会让SpEL始终使用解释执行模式,虽然会有轻微的性能损耗,但对于大多数Web应用来说可以忽略,且能立即解决间歇性错误。

3. 修改页面遍历逻辑(绕开bug)

另一种方式是调整Thymeleaf的遍历写法,避免通过反向索引访问集合:

  • 在Controller中先将executionSummary反转:
// 可以用Guava的Lists.reverse,或者自己实现反转逻辑
model.addAttribute("reversedExecutionSummary", Lists.reverse(executionSummary));
  • 然后修改页面代码,直接遍历反转后的集合:
<tbody>
<tr th:each="summary : ${reversedExecutionSummary}" 
    th:classappend="${#strings.equals(summary.state,'SUCCESS')} ? 'alert alert-success' : 'alert alert-danger'">
    <td th:text="${summary.state}"></td>
    <td th:text="${summary.result}"></td>
    <td th:text="${summary.errorCategory}"></td>
    <td th:text="${summary.count}"></td>
</tr>
</tbody>

这种写法完全绕开了索引访问,也就不会触发SpEL编译器的bug。


内容的提问来源于stack exchange,提问作者Pinaki

火山引擎 最新活动