java.lang.RuntimeException: Timeout : unable to retrieve results
at org.jbpm.task.service.responsehandlers.BlockingTaskSummaryResponseHandler.getResults(BlockingTaskSummaryResponseHandler.java:41)
解决这个问题,需要对JBPM5运行机制有一定的了解。JBPM5一般的使用方式是基于C/S架构,中间使用Apache开源框架Mina进行通信。(注意,也可以不用Mina的方式)。如果对Mina有所了解的话,一般会是Mina客户端(也可以说是JBPM5的客户端)解码器在解析JBPM5服务端返回的数据出现了问题,因此转而会去分析这个解码器,事实上也的确是这个过程中出现了问题。追踪Mina源码会发现在org.apache.mina.core.buffer.AbstractIoBuffer类的getObject(final ClassLoader classLoader)函数中以下代码:
case 1: // Non-primitive types
String className = readUTF();
Class<?> clazz = Class.forName(className, true,classLoader);
之后报出异常。程序无法加载需要使用的类,原因就出在类加载器上,那么这个ClassLoader从哪里来的呢?我们反追源码,最后找到在类ObjectSerializationDecoder的doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)方法中的 out.write(in.getObject(classLoader))这句代码处放入了这个参数,而这个参数又是在ObjectSerializationDecoder类的
public ObjectSerializationDecoder() {
this(Thread.currentThread().getContextClassLoader());
}
构造函数设置的,设置的就是线程上下文类加载器。好了,至此,我们知道就这里“走了气”了。
解决办法:
原因清楚了,就好办了,我们只要设置那个要在上文中提到的要加载类的类加载器,将当前这个线程上线文类加载器替换掉,然后用完再替换回来就行了。继续反追代码,最后我们发现MinaTaskClientConnector类的connect()方法中的
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(
new ObjectSerializationCodecFactory()));
是最早塞入这个ObjectSerializationCodecFactory类对象的,好了,这里就是始作俑者。我不想在Mina源码中修改,那么我们就继续反追,直到我们自己的代码里,最后我们发现在此位置往上一步就是:
client = new TaskClient(new MinaTaskClientConnector(
"org.drools.process.workitem.wsht.WSHumanTaskHandler",
new MinaTaskClientHandler(SystemEventListenerFactory
.getSystemEventListener())));
boolean connected = client.connect(ipAddress, port);
我的娘来,终于追到“水面”了,我们只需要在使用建立这个连结前替换掉当前上下文类加载器就行了。替换为可以加载到程序代码中需要加载类的类加载器就行了。
这个原因是:当前线程的上线问类加载器是运行Felix的应用类加载器,而要找到我们的Bundle中的类(包括Bundle classpath下的jar包中的类),则必须用我们自己Bundle的类加载器才能找到。具体的解决办法在具体的环境中不同。如果要更深入了解,需要对Felix的类加载机制有所了解。
结论:之前我为一些理论书籍或者文章误导,认为只要建立标准的OSGI Bundle就可以在不同的环境中运行。这次遇到在Equinox运行的很正常的标准Bundle迁移到Felix后,结果bug报的一塌糊涂。所以“纸上得来终觉浅,绝知此事要躬行”。OSGI是个新东西,我在解决这个问题时Google也没有找到个所以然,即使有星星点点的问题,也只是有问没有答。不得不服气,OSGI的ClassLoader问题常常搞的人是晕头转向。遇到这种问题,我们要认真分析、大胆推理、仔细验证。今天总结到这里,希望对网友有帮助。