Liferay 7.0 Gradle项目:JSF Portlet使用Kaleo API时服务注入为null问题
Liferay 7.0 Gradle项目JSF Portlet中接入Kaleo工作流API的实现方案
问题根因
- 原MVC Portlet的实现类带有
@Component注解,属于OSGi框架托管的声明式服务组件,OSGi的服务绑定机制可正常识别类上的@Reference注解,自动注入匹配的Kaleo服务实例,因此可正常运行。 - 移植到JSF Portlet场景时,直接将带
@Reference注解的代码写入JSF/CDI容器托管的类(如@ManagedBean标注的托管Bean)中,这类类完全由JSF容器管理生命周期,不纳入OSGi声明式组件的扫描范围,@Reference注解无对应处理器触发注入逻辑,最终得到的服务实例始终为null。
分步实现步骤
1. 修正build.gradle中的依赖配置
不要使用硬编码版本的compile打包方式,Kaleo相关API包由Liferay Portal运行时提供,只需配置编译期依赖即可,避免类加载冲突:
dependencies { // 替换原硬编码版本的compile配置 compileOnly group: "com.liferay.portal", name: "com.liferay.portal.workflow.kaleo.api", version: "2.0.0" compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0" }
2. 实现OSGi托管的服务桥接层
编写独立的纯OSGi组件类,不添加任何JSF/CDI相关注解,完全由OSGi框架托管,在类内部通过@Reference完成Kaleo服务的正常注入:
@Component( immediate = true, service = KaleoServiceBridge.class ) public class KaleoServiceBridge { // 该类属于OSGi托管组件,@Reference可正常生效 @Reference private KaleoTaskInstanceTokenLocalService kaleoTaskInstanceTokenLocalService; // 对外封装Kaleo服务的调用逻辑 public List<KaleoTaskInstanceToken> getAllTaskInstanceTokens() { if (kaleoTaskInstanceTokenLocalService == null) { return Collections.emptyList(); } return kaleoTaskInstanceTokenLocalService.getKaleoTaskInstanceTokens( QueryUtil.ALL_POS, QueryUtil.ALL_POS ); } }
3. 将桥接类暴露给JSF容器
Liferay的JSF扩展原生支持将OSGi组件注册为JSF托管Bean,只需在桥接类上增加@JSFComponent注解,即可自动完成注册,无需额外桥接代码:
@Component( immediate = true, service = KaleoServiceBridge.class ) // 新增该注解,将OSGi组件注册为JSF应用作用域托管Bean @JSFComponent( name = "kaleoServiceBridge", scope = "application" ) public class KaleoServiceBridge { // 原有逻辑保持不变 }
4. 在JSF场景中调用桥接服务
在JSF托管Bean或页面中直接使用已注册的桥接Bean即可,无需在JSF托管类上添加@Reference注解。例如在JSF托管Bean中调用:
@ManagedBean @RequestScoped public class WorkflowMBean { public List<KaleoTaskInstanceToken> getTaskTokenList() { // 通过JSF上下文获取已由OSGi完成服务注入的桥接实例 KaleoServiceBridge bridge = (KaleoServiceBridge) FacesContext.getCurrentInstance() .getExternalContext() .getApplicationMap() .get("kaleoServiceBridge"); return bridge.getAllTaskInstanceTokens(); } }
常见注意事项
- 禁止在JSF/CDI容器托管的类(带
@ManagedBean、@Named、@RequestScoped等注解的类)上使用@Reference注解,这类类不受OSGi组件容器管理,注解完全无效。 - 不要将Kaleo的LocalService实例直接存入JSF请求/会话作用域,服务引用的生命周期与OSGi组件绑定,硬引用可能在服务版本更新后出现失效问题,所有调用统一通过桥接层完成。
- 依赖配置不要将Kaleo API包打进自有bundle,使用
compileOnly配置即可,避免和Portal运行时提供的类产生版本冲突。
内容的提问来源于stack exchange,提问作者Chirag Lakhamani
相关产品推荐
相关产品推荐

