我有一个具有上传功能的Web应用程序,它包含上传包含java应用程序的包(它可能包含多个依赖项)
为此,对于每个上传的应用程序,我都要创建一个自定义类加载器来动态加载应用程序类路径。 解决方案正常工作,直到我上传新应用程序时出现此错误:
javax.xml.stream.FactoryConfigurationError: Error creating stream factory: java.lang.ClassNotFoundException: de.odysseus.staxon.json.stream.impl.JsonStreamFactoryImpl
我已验证我上传的软件包包含staxon,并且还验证了我的自定义类加载器可以加载该类:
Object a=Class.forName("de.odysseus.staxon.json.stream.impl.JsonStreamFactoryImpl",true , classLoader).newInstance();
那么,为什么这个例外并特意为这个jar?
答案 0 :(得分:0)
当您调用Class.forName(className, initialize, classLoader)
时,您要求JVM使用该自定义类加载器加载类。如果您没有指定ClassLoader
- 例如只需调用Class.forName(className)
,那么JVM将使用ClassLoader
称为" context ClassLoader"为线程。每个线程都有其中一个,您的代码可以轻松地更改上下文类加载器。
如果你有一些代码导致一个类加载 - 就像这样:
MyClass foo = new MyClass();
MyClass
类将由ClassLoader
加载,如果它尚未加载。如果类尚未加载,则无法调用构造函数并提供ClassLoader
来加载类。在这种情况下,线程的上下文ClassLoader
是用户。
此外,如果你调用一些你无法控制的代码,那么代码可以通过很多方式加载其他类,并且由于你无法控制那些代码,所以线程“无法控制”。也将使用上下文ClassLoader
。
那么,你如何设置线程的上下文ClassLoader
?易:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader myClassLoader = ...; // You figure this out
try
{
Thread.currentThread().setContextClassLoader(myClassLoader);
// Do work that requires your ClassLoader to work
}
finally
{
// Always restore the previous CCL after work is done
Thread.currentThread().setContextClassLoader(cl);
}
您要做的另一件事是确保您的自定义ClassLoader
将任何类加载请求委托给父ClassLoader
。父亲ClassLoader
可能应该是ClassLoader
,如果您没有尝试使用自己的ClassLoader
,则自然会使用该ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader myClassLoader = new MyClassLoader(cl); // Try 'cl' before your custom class loading
try
{
Thread.currentThread().setContextClassLoader(myClassLoader);
// Do work that requires your ClassLoader to work
}
finally
{
// Always restore the previous CCL after work is done
Thread.currentThread().setContextClassLoader(cl);
}
。
所以,您可能需要以下内容:
from gensim.models import Word2Vec
您可以在以下几个参考资料中找到有关from gensim.models import word2vec
s,特别是TCCL的更多信息: