一、背景
最近在使用 Springboot + Activiti6 重构和优化审批流程闭环管理的项目,前期由于该项目会不停的将软件应用到不同的用户与场景,同时可预知的未来可能还会存在各种用户的各种特定需求,所以为了以后的软件升级和代码维护,所以我准备使用插件的模式来做项目的设计。
不同用户的项目核心程序使用一套统一的核心逻辑代码,特定功能通过不同的用户插件实现特定功能,不影响其他用户版本的软件功能,核心代码通过接口的方式为插件提供功能接入,在应对不同用户的不同需求的时候只需要扩展接口开发插件,在插件中实现具体的核心功能逻辑即可。
因此在插件框架的选择上我选择了pf4j,因为使用起来比较简单。pf4j每个插件通过不同的ClassLoader将对应插件内的接口实现类加载到程序中。
二、项目设计
按照上面的思路,我将项目分为了三个模块
- activiti-core
负责整合项目的核心逻辑,包括前端接口,流程处理逻辑,与插件交互逻辑等应用的核心逻辑 - activiti-plugin-api
用来定义插件应该实现的接口,activiti-core 通过该模块与所有实现了这些插件api的插件进行交互。 - activiti-plugin-xxx
所有实现了 activiti-plugin-api 对应扩展接口的插件集合,用于处理不同用户的特定的业务逻辑。(包括不同要求的任务通知、不同要求的审批单生成逻辑等)
三、存在的问题
首先,根据上面的设计,所有的插件是不应该引用任何activiti-core的代码,在插件层面应该是对activiti-core模块没有任何感知的,插件只应该通过实现对应的 activiti-api 接口达到与activiti-core 交互的目的。
其次,具体的流程文件定义是在插件中的,流程中很大概率会存在类似于 serviceTask 这样的任务节点,比如:
<serviceTask id="servicetask1" name="文档上传" activiti:class="com.anke.activiti.plugin.prodef.jisan.UploadFileService">
<extensionElements>
<activiti:field name="uploadFile">
<activiti:expression><![CDATA[${warnNoticeDoc}]]></activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>
这里我定义了一个文件上传的serviceTask节点,指定了使用 com.anke.activiti.plugin.prodef.jisan.UploadFileService 这个类来进行处理。
ClassNotFoundException
但是,由于PF4J每一个插件使用不同的ClassLoader,而Activiti的核心处理逻辑在activiti-core这个模块里面,这就会导致流程处理在执行到该节点的时候报错,由于不在同一个ClassLoader下,所以无法找到该节点的处理类。
Caused by: org.activiti.engine.ActivitiClassLoadingException: Class not found: com.anke.activiti.plugin.prodef.jisan.UploadFileService
at org.activiti.engine.impl.util.ReflectUtil.loadClass(ReflectUtil.java:87)
at org.activiti.engine.impl.util.ReflectUtil.instantiate(ReflectUtil.java:134)
... 122 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.anke.activiti.plugin.prodef.jisan.UploadFileService
at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader.loadClass(TomcatEmbeddedWebappClassLoader.java:72)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.activiti.engine.impl.util.ReflectUtil.loadClass(ReflectUtil.java:288)
at org.activiti.engine.impl.util.ReflectUtil.loadC

本文档描述了在使用SpringBoot和Activiti6重构审批流程项目时,采用插件模式遇到的ClassNotFoundException问题。作者将项目分为activiti-core、activiti-plugin-api和activiti-plugin-xxx三个模块,旨在实现核心逻辑与特定功能的解耦。然而,由于pf4j的类加载机制,导致流程执行时找不到类。为解决此问题,作者自定义了一个ClassLoader,使其先尝试父ClassLoader加载,若失败则遍历所有插件的ClassLoader,成功解决了问题。
最低0.47元/天 解锁文章
1250

被折叠的 条评论
为什么被折叠?



