Drools Engine 8.43.0.Final中如何序列化KieBase
解决方案
针对KieBase不可序列化无法存入Redis,以及KieSession反序列化依赖KieBase的问题,提供以下几种可行方案:
1. 序列化KieBase的构建配置而非实例本身
KieBase的核心是规则集合和配置,与其序列化不可序列化的KieBase实例,不如持久化构建它的原始配置,取出时重新生成KieBase:
- 步骤:
- 收集构建KieBase所需的所有资源:将KieFileSystem中的
.drl规则文件、决策表等资源转为字节数组或字符串; - 导出KieBase的配置:通过
kieBase.getKieBaseConfiguration().toProperties()获取配置属性; - 将上述资源和配置打包成一个可序列化的POJO(比如
KieBaseCacheEntry),存入Redis; - 从Redis取出时,通过KieServices重新加载资源、应用配置,重建KieBase:
// 存入时的逻辑 KieServices kieServices = KieServices.Factory.get(); KieFileSystem kfs = kieServices.newKieFileSystem(); // 假设已添加规则文件到kfs byte[] drlContent = kfs.read("src/main/resources/rules/myRules.drl"); Properties kieBaseProps = kieServices.newKieBaseConfiguration().toProperties(); KieBaseCacheEntry cacheEntry = new KieBaseCacheEntry(drlContent, kieBaseProps); // 将cacheEntry序列化存入Redis // 取出时重建KieBase KieBaseCacheEntry cachedEntry = redisTemplate.get("kiebase-key"); KieFileSystem newKfs = kieServices.newKieFileSystem(); newKfs.write("src/main/resources/rules/myRules.drl", cachedEntry.getDrlContent()); KieBaseConfiguration config = kieServices.newKieBaseConfiguration(cachedEntry.getKieBaseProps()); KieContainer kieContainer = kieServices.newKieContainer(kieServices.newKieModule(newKfs)); KieBase kieBase = kieContainer.newKieBase(config);
- 收集构建KieBase所需的所有资源:将KieFileSystem中的
2. 实现自定义序列化器处理KieBase
通过自定义序列化逻辑,提取KieBase的可持久化信息,绕过默认的序列化限制:
- 针对Redis的序列化器,自定义
RedisSerializer<KieBase>:public class KieBaseRedisSerializer implements RedisSerializer<KieBase> { @Override public byte[] serialize(KieBase kieBase) throws SerializationException { // 提取规则内容和配置 Properties props = kieBase.getKieBaseConfiguration().toProperties(); Collection<KiePackage> packages = kieBase.getKiePackages(); // 将packages转为可序列化的格式(比如把每个package的规则转为字符串) List<String> ruleContents = new ArrayList<>(); for (KiePackage pkg : packages) { for (Rule rule : pkg.getRules()) { ruleContents.add(rule.getPackageName() + ":" + rule.getName() + ":" + rule.getLhs() + rule.getRhs()); } } // 打包成JSON或其他序列化格式 KieBaseSerializedDTO dto = new KieBaseSerializedDTO(props, ruleContents); return new ObjectMapper().writeValueAsBytes(dto); } @Override public KieBase deserialize(byte[] bytes) throws SerializationException { KieBaseSerializedDTO dto = new ObjectMapper().readValue(bytes, KieBaseSerializedDTO.class); KieServices kieServices = KieServices.Factory.get(); KieFileSystem kfs = kieServices.newKieFileSystem(); // 重新构建规则文件并写入kfs for (String ruleContent : dto.getRuleContents()) { // 解析规则内容,生成.drl文件并写入 String[] parts = ruleContent.split(":"); String pkgName = parts[0]; String ruleName = parts[1]; String lhs = parts[2]; String rhs = parts[3]; String drl = "package " + pkgName + "\nrule " + ruleName + "\nwhen " + lhs + "\nthen " + rhs + "\nend"; kfs.write("src/main/resources/rules/" + ruleName + ".drl", drl.getBytes()); } KieBaseConfiguration config = kieServices.newKieBaseConfiguration(dto.getProps()); KieContainer kieContainer = kieServices.newKieContainer(kieServices.newKieModule(kfs)); return kieContainer.newKieBase(config); } } - 配置RedisTemplate使用该序列化器,即可直接将KieBase存入/取出Redis。
3. 优化KieSession缓存逻辑,关联KieBase配置
如果仍需缓存KieSession,可将KieSession与对应的KieBase配置绑定缓存:
- 缓存时,将KieSession序列化后的字节数组,与对应的KieBase配置POJO(如方案1中的
KieBaseCacheEntry)存入同一个Redis键或关联键; - 取出时,先通过KieBase配置重建KieBase,再用该KieBase反序列化KieSession:
// 缓存KieSession和KieBase配置 byte[] sessionBytes = serializeKieSession(kieSession); redisTemplate.opsForHash().put("session-cache", "session-1", sessionBytes); redisTemplate.opsForHash().put("session-cache", "session-1-kb-config", cacheEntry); // 取出反序列化 KieBaseCacheEntry cachedConfig = (KieBaseCacheEntry) redisTemplate.opsForHash().get("session-cache", "session-1-kb-config"); KieBase kieBase = rebuildKieBase(cachedConfig); byte[] sessionBytes = (byte[]) redisTemplate.opsForHash().get("session-cache", "session-1"); KieSession kieSession = kieBase.newKieSession(); ((StatefulKnowledgeSession) kieSession).restore(sessionBytes);
内容的提问来源于stack exchange,提问作者Tamil Prabhu
相关产品推荐
相关产品推荐

