springboot集成drools不能正常运行-类加载器导致的坑

在Spring Boot项目中引用Drools进行规则推理时,JUnit测试正常,但项目启动规则失效。经排查,问题由Spring Boot热部署工具devtools导致,它采用不同类加载器加载类,与Drools的类加载器不一致,使Drools无法识别。解决办法是去掉devtools的Maven依赖。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

在springboot项目中引用drools进行规则推理时,明明用junit测试drools的规则可以正常运行,但是当从项目中启动时候发现规则无法正常运行,凡是涉及fact对象的所有都失效,如果将规则的条件改为eval(true)则可以正常运行。

解决:

初步猜测是drools的工作内存出现的问题(working memory),因为drools的insert fact会将对象放置在working memory中,猜测是不是dubbo线程引起的,所以将推理那块改为多线程的方式,发现问题同样存在。

最后在一个类似的帖子中:https://blog.youkuaiyun.com/xx123698/article/details/84784741 发现类似的相关问题,所以尝试下发现果然可以。就是springboot引入了热部署工具spring-boot-devtools导致的锅。
在这里插入图片描述
在帖子中没有进行很详细的说明,只是大体说了下类加载器的问题,确实是因为类加载器的问题,在drools的官方网站中有人提出了这个问题,并认为是个bug,但是drools的开发者认为这不是一个bug,地址:https://issues.jboss.org/browse/DROOLS-1540
在这里插入图片描述
说白了就是drools用的是lancher classloader,而devtools会把我们自己编写的model认为是会随时更改的类,所以采用的是Restart ClassLoader类加载器进行加载(为了快速进行热部署),devtools会有两个类加载器,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为 Restart ClassLoader。
当采用Launcher ClassLoader加载的A 类与Restart Class Loader的A类进行对比时,发现不一致,所以drools引擎自然无法进行识别(这点与大哥@干净的句号说的一致,大哥就是大哥,吃的盐果然不少)。

springboot 项目启动(采用devtools工具):
在这里插入图片描述
drools采用的类加载器是AppClassLoader,而insert的fact对象采用的类加载器为:
在这里插入图片描述
可以看到采用的是RestartClassLoader,因为类加载器不一致,并不是由双亲委派模型的下的上级类加载器加载进来,对于一个类,由不同的类加载器实例加载的话,会在方法区产生两个不同的类,彼此不可见,并且在堆中生成不同Class实例(所有通过正常双亲委派模式的类加载器加载的classpath下的和ext下的所有类在方法区都是同一个类,堆中的Class实例也是同一个)。因为两者不一致,所以drools在workingmemory中使用的是AppAppClassLoader的实例自然无法找到由RestartClassLoader加载的实例。

多说一点,RestartClassLoader打破了双亲委派模型,其源码:
在这里插入图片描述
所以为了满足热更新的需求,不需要父加载器重新生成加载,只需要自身去查找加载类即可,这也是其能热更新的主要原因。

在Junit测试下,两者采用的都是AppClassLoader:
在这里插入图片描述

所以解决办法就是将devtools的maven依赖去掉即可,或者采用drools官网中说明的其它方法,因为太多英文没耐心看下去。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值