Java 如何让Drools访问动态加载的类?
我试图在运行时使用类加载器从.class文件加载类,并在Drools规则(Drools 7.52.0)中使用它们。我正在使用这个自定义类加载器,它从文件中读取并使用Java 如何让Drools访问动态加载的类?,java,classloader,drools,Java,Classloader,Drools,我试图在运行时使用类加载器从.class文件加载类,并在Drools规则(Drools 7.52.0)中使用它们。我正在使用这个自定义类加载器,它从文件中读取并使用ClassLoader.defineClass()加载类。它类似于URLClassLoader: package example; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStr
ClassLoader.defineClass()
加载类。它类似于URLClassLoader:
package example;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DynamicClassLoader extends ClassLoader {
public DynamicClassLoader(ClassLoader parent) {
super(parent);
}
/**
* Define a class from a .class file and return it
* @param filepath path to a .class file
* @return new Class or null if error
*/
public Class<?> classFromFile(String filepath) {
try {
// Read .class file and write bytes to buffer
BufferedInputStream input = new BufferedInputStream(new FileInputStream(filepath));
// Write file contents to buffer
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1){
buffer.write(data);
data = input.read();
}
byte[] classData = buffer.toByteArray(); // contents of .class file
input.close();
return defineClass(null, classData, 0, classData.length);
} catch (IOException | ClassFormatError e) {
e.printStackTrace();
}
return null;
}
}
编译此规则(使用KieBuilder.buildAll()
)会出现错误
规则编译错误只能导入类型。事实。一个人决定一个包裹。事实。无法将人员解析为类型。
如果我没有将类加载器传递给KieBuilder,我会得到另外两个错误:
无法解析对象类型“Person”$p无法解析。
因此,我的类加载器正在做一些事情,但没有让Drools完全访问它加载的任何类。我怎样才能解决这个问题?我在这个问题上花了好几天的时间,但我找不到任何有帮助的东西。看起来任何加载的类文件的内容在编译之前都需要写入文件系统 因此,要让Drools完全访问类,需要以下内容:
ClassLoader类加载器;
//使用classLoader加载外部类
...
//将类定义复制到文件系统
对于(/*每个加载的类*/){
字符串filename=packageName+'/'+className+“.class”;
write(文件名,byteArrayOfClassFileContents);
}
//将类加载器传递给newKieBuilder和newKieContainer
KieServices=KieServices.Factory.get();
KieBuilder kBuilder=kServices.newKieBuilder(kFileSys,classLoader.buildAll();
KieContainer kContainer=kServices.newKieContainer(
kServices.getRepository().getDefaultReleaseId(),classLoader);
请注意,将类文件写入文件系统根目录中的包中是很重要的。例如,类
foo.bar.Baz
的定义应写入“foo/bar/Baz.class”
在加载和编译规则时,该类必须位于类路径上。@roddyoffrozenpeas我需要在运行时加载类,因此在编译时将它们置于类路径上是不可能的。幸运的是,我的解决方案奏效了。不,我不是这么说的。在编译规则时,它们需要位于类路径上。您可以在示例代码中这样做;我只是为未来的读者指出这一点。您无法编译规则,然后加载类。
package example;
import java.io.IOException;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.runtime.KieSession;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
public class Main {
private static KieServices kServices = KieServices.Factory.get();
private static KieFileSystem kFileSys;
private static KieSession kSession;
private static DynamicClassLoader classLoader = new DynamicClassLoader(Main.class.getClassLoader());
public static void main(String[] args) throws IOException, ClassNotFoundException {
// Load Person class
classLoader.classFromFile("Person.class");
// Instantiate Person
Class<?> personClass = classLoader.loadClass("facts.Person");
Object person = null;
try {
// Instantiate person and access methods using reflection
person = personClass.getConstructor(String.class, Integer.class).newInstance("Alice", 49);
System.out.println(person.getClass() + ": name = " +
(String) personClass.getMethod("getName").invoke(person));
} catch (Exception e) {
System.out.println("Error instantiating person");
e.printStackTrace();
}
// Create a KieSession with a rule that uses the Person class
String drl = String.join("\n",
"import facts.Person;",
"rule \"person\"",
" when",
" $p : Person()",
" then",
" System.out.println($p.getName());",
"end"
);
initializeKieSession(drl);
kSession.insert(person);
kSession.fireAllRules();
}
/**
* Create a KieSession using the given ruleset
* @param drl a ruleset string in Drools Rule Language
*/
private static void initializeKieSession(String drl) {
// Create module model
KieModuleModel kModMod = kServices.newKieModuleModel();
KieBaseModel kBaseMod = kModMod.newKieBaseModel("KBase_std").setDefault(true);
kBaseMod.newKieSessionModel("KSession_std").setDefault(true);
// Create file system with module model
kFileSys = kServices.newKieFileSystem();
kFileSys.writeKModuleXML(kModMod.toXML());
// Write rules
kFileSys.write("src/main/resources/person.drl", drl);
KieBuilder kBuilder = kServices.newKieBuilder(kFileSys, classLoader).buildAll();
boolean errors = kBuilder.getResults().hasMessages(Message.Level.ERROR);
if (errors) {
for (Message message : kBuilder.getResults().getMessages())
System.out.println(message.getText());
}
// new KieSession
kSession = kServices.newKieContainer(
kServices.getRepository().getDefaultReleaseId(), classLoader).getKieBase().newKieSession();
}
}