所以我有一个Spring Boot应用程序,它从以下路径加载外部jar:
java -cp "main-0.0.1-SNAPSHOT.jar" -Dloader.path="%USERPROFILE%\Addons\" -Dloader.main=moe.ofs.backend.BackendApplication org.springframework.boot.loader.PropertiesLauncher
主jar在编译时不知道外部jar。外部jar通过指定像“插件”或“插件”一样加载
Dloader.path
所有外部jar都依赖于“main-0.0.1-SNAPSHOT. jar”的接口,它们应该或多或少地执行对象序列化。该接口称为Configurable
,它提供了两个默认方法,如下所示:
default <T extends Serializable> void writeFile(T object, String fileName) throws IOException {
Path configFilePath = configPath.resolve(fileName + ".data");
FileOutputStream fileOutputStream = new FileOutputStream(configFilePath.toFile());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.close();
}
default <T extends Serializable> T readFile(String fileName) throws IOException, ClassNotFoundException {
Path configFilePath = configPath.resolve(fileName + ".data");
FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
return (T) objectInputStream.readObject();
}
外部jar中的类实现了这个接口,它们调用readFile()
和WriteFile()
。
writeFile()
工作正常,似乎不会引起任何问题<然而,code>readFile()抛出了一个ClassNotFoundException
,这就是我想弄明白的。
java.lang.ClassNotFoundException: moe.ofs.addon.navdata.domain.Navaid
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:719)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1922)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1805)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2096)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at java.util.ArrayList.readObject(ArrayList.java:797)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1170)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2232)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2123)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at moe.ofs.backend.Configurable.lambda$readFile$0(Configurable.java:186)
at java.lang.Thread.run(Thread.java:748)
经过一些测试,在我看来ClassNotFoundException
是由Class.forName()抛出的,因为默认的ClassLoader很难找到moe.ofs.addon.navdata.domain.Navaid
,这是我试图反序列化的类。
导航设备实现可串行化,并且它还有一个静态的最终长serialVersionUID。
我曾希望可以通过为当前线程设置上下文类加载器来解决这个问题,以便ObjectInputStream将使用Spring Boot类加载器来解析Navaid类:
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
当打印出来时,会显示
Thread.currentThread().getContextClassLoader() = org.springframework.boot.loader.LaunchedURLClassLoader@7a0b4753
除了ObjectInputStream#readObject
仍然抛出ClassNotFoundException
。如果我显式调用从Spring Boot加载器加载Navaid类,例如:
getClass().getClassLoader().loadClass("moe.ofs.addon.navdata.domain.Navaid");
它返回一个没有任何问题的导航设备实例。
正如所料,当直接呼叫时
Class.forName("moe.ofs.addon.navdata.domain.Navaid")
即使线程上下文加载器已显式设置为LaunchedURLClassLoader,也会引发一个ClassNotFoundException
ObjectInputStream#readObject
总是通过调用系统默认类加载器来加载类来尝试解析类。
然后我尝试使用LaunchedURLClassLoader
加载ObjectInputStream
,但实例仍然使用系统默认类加载器中的Class.forName()
。
ClassLoader cl = getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
System.out.println("Thread.currentThread().getContextClassLoader() = " + Thread.currentThread().getContextClassLoader());
Class<?> tClass = getClass().getClassLoader().loadClass("java.io.ObjectInputStream");
System.out.println("tClass = " + tClass);
Path configFilePath = configPath.resolve(fileName + ".data");
FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());
Constructor<?> constructor = tClass.getConstructor(InputStream.class);
ObjectInputStream objectInputStream = (ObjectInputStream) constructor.newInstance(fileInputStream);
objectInputStream.readObject(); // throws ClassNotFoundException
欢迎您的任何意见。提前谢谢。
据我所知,您应该重写ObjectInputStream上的方法
诸如此类:
default <T extends Serializable> T readFile(String fileName, ClassLoader loader) throws IOException, ClassNotFoundException {
Path configFilePath = configPath.resolve(fileName + ".data");
FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream){
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
try {
return Class.forName(desc.getName(), false, loader);
} catch(ClassNotFoundException cnfe) {
return super.resolveClass(desc);
}
}
};
return (T) objectInputStream.readObject();
}
我自己从未尝试过,但值得一试。
如果您的项目中有Commons io,也http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/input/ClassLoaderObjectInputStream.html。
https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/input/ClassLoaderObjectInputStream.java
问题内容: 是否有可能从while循环中读取内容,该内容将因套接字超时引发的异常而终止 问题答案: 当您说“不工作”时,由于编译器消息中所述的原因,您真正的意思是“不编译”:不是表达式,也不能在条件中声明变量。 但是该代码仍然无效。读取到任意流的末尾的正确方法是catch ,例如,如下所示: 请注意,在意见建议,以测试返回值是 不 正确的。仅当您写了时,它才会返回。
本文向大家介绍Java ObjectInputStream readObject()方法(带示例),包括了Java ObjectInputStream readObject()方法(带示例)的使用技巧和注意事项,需要的朋友参考一下 ObjectInputStream类方法 readObject()方法在java.io包中可用。 readObject()方法用于从此ObjectInputStream
问题内容: 我陷入了这个非常奇怪的问题。在客户端中,我传递的对象是 在服务器中,我正在读取对象 我的问题是为什么我会出现EOF异常。我对对象输入流的理解是,当我调用readObject()时应该阻塞直到获得对象,这样才能知道是否达到了eof?请帮忙! 这就是我创建对象流的方式 另外,在我写完对象并刷新之后,我应该关闭流。我不会关闭它,因为对象是从代码的不同部分开始一个接一个地定期编写的。 问题答案
我在面向 Web 开发人员的 Eclipse Java EE IDE 中有一个专家项目。在运行 Tomcat 时,我收到一个类的错误,我可以看到我已经包含该类。 我的问题是-因为Tomcat Apache,我必须将这些JAR添加到其他位置吗? 错误: 严重:Servlet /Resource抛出load()异常java.lang.ClassNotFoundException:org.odata4j
我正在完成一个项目,我必须将它部署为一个jar文件,在eclipse中它工作得很好,我的项目依赖于两个库,这两个库也都依赖于dll文件。我已经将这些DLL的路径添加到每个外部JAR的本机库位置。然后,我使用eclipse可运行的jar文件导出向导将project导出为一个jar文件我在指定的位置得到了jar文件,它运行了,但是当我单击一个调用我得到的库之一的按钮时,我得到了java.lang.Un
我有一个jar文件,它有下面的类来加载一些属性- 在我的Spring启动项目中,上面的class/jar是一个依赖项。 我如何指定在哪里寻找这个属性“公共列表”来加载我的项目? 或 我是否需要修改类/jar,并使用属性源注释指定在哪里查找这些公共列表值的属性文件? 我bootstrap.properties以下行- xyz.yaml配置服务器 通过查看我的spring boot应用程序的env属性