2

我正在开发一个使用流口水来评估某些对象的系统。但是,这些对象可以是在运行时使用 jodd 加载的类。我可以使用以下功能很好地加载文件:

 public static void loadClassFile(File file) {
    try {
        // use Jodd ClassLoaderUtil to load class into the current ClassLoader
        ClassLoaderUtil.defineClass(getBytesFromFile(file));
    } catch (IOException e) {
        exceptionLog(LOG_ERROR, getInstance(), e);
    }
 }

现在假设我创建了一个名为 Tire 的类并使用上面的函数加载它。有没有办法可以在我的规则文件中使用 Tire 类:

rule "Tire Operational"
when
    $t: Tire(pressure == 30)
then

end

现在,如果我尝试添加此规则,我会收到一条错误消息,提示无法解析 ObjectType Tire。我的假设是我会以某种方式需要在规则中导入轮胎,但我不确定如何做到这一点。

4

1 回答 1

1

从第 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()方法来显式定义每个类会更好。

于 2012-07-06T21:43:03.710 回答