You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Liferay 7登录片段部署后首次访问EL依赖异常求助

解决Liferay片段钩子首次访问时EL工厂找不到的问题

我之前也碰到过类似的情况,给你梳理下问题原因和可行的解决办法:

问题场景还原

你给login.jsp做的登录片段原本运行正常,后来为了从自定义表取数据,在scriptlet里加了XYZLocalServiceUtil的调用。服务本身调用没问题,但部署片段钩子后第一次访问页面就会报EL相关的错误,直接导致Portlet不可用,刷新页面后又能恢复正常。报错核心信息是:

07:17:00,237 ERROR [http-nio-9080-exec-9][PortletRequestDispatcherImpl:265] Unable to dispatch request: javax.el.ELException: Provider com.sun.el.ExpressionFactoryImpl not found
07:17:00,242 ERROR [http-nio-9080-exec-9][PortletServlet:111] javax.portlet.PortletException: org.apache....

问题根源

这种"首次访问报错、刷新就好"的情况,大概率是类加载器初始化顺序冲突导致的。Liferay的片段钩子在首次加载时,scriptlet里的ServiceUtil调用提前触发了某些类加载操作,打乱了EL表达式工厂的正常初始化流程,导致com.sun.el.ExpressionFactoryImpl没被正确加载。

可行解决方案

1. 避免在JSP scriptlet里直接调用LocalServiceUtil(最推荐)

Liferay本身不建议在JSP里直接写scriptlet代码,更规范的做法是通过MVC机制预处理数据:

  • 自定义一个MVCRenderCommand,在里面调用XYZLocalServiceUtil获取数据,把数据放到request属性里
  • 然后在login.jsp里通过EL表达式直接读取request里的数据,比如${customData}
    这样不仅能避开类加载顺序的问题,代码的可维护性也会更高。

2. 手动提前初始化EL工厂类

如果实在要保留scriptlet里的ServiceUtil调用,可以在调用之前手动触发EL工厂类的加载,在scriptlet最开头加上这段代码:

try {
    // 强制加载EL工厂类,避免首次访问时找不到
    Class.forName("com.sun.el.ExpressionFactoryImpl");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
// 后面再写你的XYZLocalServiceUtil调用代码

这样能确保EL工厂类在ServiceUtil调用之前被加载,解决首次访问的依赖缺失问题。

3. 检查片段钩子的类加载配置

打开你的片段钩子的liferay-hook.xml文件,看看有没有设置<class-loader>属性。如果设置了<class-loader>portal</class-loader>,可能会导致应用类和门户类的加载冲突,改成默认配置(去掉这个属性)或者设置成<class-loader>application</class-loader>试试。

调试小技巧

如果还是不确定问题点,可以在Liferay的日志配置里开启类加载相关的debug日志,看看首次访问时com.sun.el.ExpressionFactoryImpl的加载路径,对比刷新后的加载情况,就能更精准定位冲突的原因。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:12:57