从第 3 版开始就没有使用 Drools,但无论如何都会尝试提供帮助。当您以这种方式加载类时(动态地,在运行时,无论您使用的是 Class.forName() 还是 Jodd),加载的类名根本无法在代码中显式使用。我相信我们可以使用以下 sudo 代码简化您的问题,您首先加载一个类,然后尝试使用它的名称:
defineClass('Tire.class');
Tire tire = new Tire();
这显然不起作用,因为轮胎类型在编译时不可用:编译器不知道您将在执行期间加载什么类型。
可行的是让Tire 实现一些接口(例如VehiclePart)。因此,您可以使用以下 sudo 代码:
Class tireClass = defineClass('Tire.class');
VehiclePart tire = tireClass.newInstance();
System.out.println(tire.getPartName()); // prints 'tire' for example
然后也许你可以在接口 VehiclePart 和 getPartName() 属性上构建你的 Drools 规则。
附录
仅当接口涵盖动态加载类的所有属性时,上述内容才有意义。在大多数情况下,这不是一个有效的解决方案:动态加载的类根本不共享属性。所以,这是另一种方法。
这个问题可以通过“扩展”类加载器类路径来解决,而不是使用显式类加载。请注意,这是一个黑客!
在 Jodd 中,有一个方法:ClassLoaderUtil.addFileToClassPath(),可以在运行时向类加载器添加文件或路径。所以这里是对我有用的步骤:
1)将所有动态创建的类放入某个根文件夹中,考虑到它们的包。例如,假设我们要使用一个jodd.samples.TestBean类,它有两个属性:数字(int)和一个值(字符串)。然后我们需要把这个类放到root/jodd/samples文件夹中。
2)构建所有动态类后,扩展类加载器路径:
ClassLoaderUtil.addFileToClassPath("root", ClassLoader.getSystemClassLoader());
3) 在创建 KnowledgeBuilder 之前加载类并创建它:
Class testBeanClass = Class.forName("jodd.samples.TestBean");
Object testBean = testBeanClass.newInstance();
4)此时您可以使用BeanUtils(来自Jodd,例如:)来操作testBean实例的属性
5)创建 Drools 东西并将插入 testBean 添加到会话中:
knowledgeSession.insert(testBean);
6)在规则文件中使用它:
import jodd.samples.TestBean;
rule "xxx"
when
$t: TestBean(number == 173)
then
System.out.println("!!!");
end
这对我有用。请注意,在第 2 步中,您可以尝试使用不同的类加载器,但您可能需要它通过 KnowledgeBuilderConfiguration(即 PackageBuilderConfiguration)将其传递给 KnowledgeBuilderFactory。
另一种解决方案
另一种解决方案是简单地将所有对象属性复制到映射中,并在规则文件中处理映射。所以你可以在第 4 步使用这样的东西:
Map map = new HashMap();
BeanTool.copy(testBean, map);
稍后(步骤#5)将映射添加到 Drools 上下文而不是 bean 实例。在这种情况下,使用defineClass()方法来显式定义每个类会更好。