在技术群里遇到网友问到一个function 调用global报错的问题,这里写个程序复现一下先。
1.定义一个service 一会儿作为global set到drools kiesession
package com.helloworld.Service;
public class TestService {
public void testGlobal(String str){
System.out.println("java application print:"+str);
}
}
2. DRL文件
package com.hello;
global com.helloworld.Service.TestService myService
function boolean myfunction(String str){
myService.testGlobal(str);
return true;
}
rule "testGlobal"
when
eval( myfunction("hello global",myService))
then
System.out.println("rule print success!");
end
3.调用
KieServices ks = KieServices.Factory.get();
KieContainer kc = ks.getKieClasspathContainer();
KieSession session = kc.newKieSession();
//创建TestService实例对象,加入到drools
TestService service = new TestService();
session.setGlobal("myService",service);
//触发规则
session.fireAllRules();
4.报错
Exception in thread "main" java.lang.RuntimeException: Error while creating KieBase[Message [id=1, kieBase=defaultKieBase, level=ERROR, path=E:\ideaTest\droolsTemplate\target\classes\testGlobal.drl, line=5, column=0
text=[ function myfunctionmyfunction (line:5): myService cannot be resolved
]], Message [id=2, kieBase=defaultKieBase, level=ERROR, path=E:\ideaTest\droolsTemplate\target\classes\testGlobal.drl, line=10, column=0
text=Rule Compilation error The import com.hello.Myfunction cannot be resolved
The method myfunction(String, TestService) is undefined for the type Rule_testGlobal1826430642], Message [id=3, kieBase=defaultKieBase, level=ERROR, path=E:\ideaTest\droolsTemplate\target\classes\testGlobal.drl, line=-1, column=0
text=Error importing : 'com.hello.Myfunction.myfunction']]
at org.drools.compiler.kie.builder.impl.KieContainerImpl.getKieBase(KieContainerImpl.java:377)
at org.drools.compiler.kie.builder.impl.KieContainerImpl.getKieBaseFromKieSessionModel(KieContainerImpl.java:575)
at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:551)
at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:458)
at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:441)
at com.helloworld.action.TestGlobalAction.main(TestGlobalAction.java:12)
14:44:54.995 [main] ERROR org.drools.compiler.kie.builder.impl.KieProject - Unable to build KieBaseModel:defaultKieBase
[ function myfunctionmyfunction (line:5): myService cannot be resolved
]
Rule Compilation error : [Rule name='testGlobal']
com/hello/Rule_testGlobal1826430642.java (2:138) : The import com.hello.Myfunction cannot be resolved
com/hello/Rule_testGlobal1826430642.java (8:445) : The method myfunction(String, TestService) is undefined for the type Rule_testGlobal1826430642
Error importing : 'com.hello.Myfunction.myfunction'
5.猜想
从异常信息中可以看出是创建默认KieBase 时出现的异常,创建知识库报错基本可以认为是DRL编写有问题。
function是放在drl源文件中的代码块,其本质就是个函数,用来抽取和封装具有参数不同,但处理具有相同代码逻辑。再来看Global 它实际是某数据类型的实例对象,尽管Global是全局的,但是函数里直接调用实例……Emm……,那猜测大概就是这里有问题吧。基于这个猜想我给出一个改造方案。
6.改造DRL文件,将Global 变量作为参数传递到function,function通过形参调用Global,如下:
package com.hello;
//引入Global中实例对象的数据类型
import com.helloworld.Service.TestService
//引入Global
global com.helloworld.Service.TestService myService
//function 增加 Global 中实例对象的数据类型 的形参
function boolean myfunction(String str,TestService t){
//通过形参调用Global中实例对象的方法
t.testGlobal(str);
return true;
}
rule "testGlobal"
when
//将Global 中实例对象作为参数传入function
eval( myfunction("hello global",myService))
then
System.out.println("rule print success!");
end
执行结果:
java application print:hello global
rule print success!
嗯!OJBK!