【发布时间】:2019-10-31 17:13:58
【问题描述】:
更新:添加了更多信息,因为解决方法无法可靠运行
我有一个 RMI 模块,我使用自定义类加载器 vie spring bean 加载该模块。此类加载器也用于加载该模块。
ClassLoader 继承自 URLClassLoader。该自定义类加载器的父类加载器设置为 AppClassLoader。
在这个模块中,我根据这个类加载器使用 conxt 类加载器启动 RMI 注册表。
现在,如果我进行 RMI 调用,RMI 注册表:
- 能够在我提供给类加载器的 URL 路径中发现类
- 无法在父类加载器中发现类。
通过在 RMI 服务器端启用调试
"-Djava.rmi.server.logCalls=true",
"-Dsun.rmi.server.logLevel=VERBOSE",
"-Dsun.rmi.loader.logLevel=VERBOSE",
我能够验证 RMI 注册表使用了正确的类加载器(也是对父级的引用)
我尝试将来自 AppClassLoader 的 URL 添加到我的 ClassLoader。首先,它似乎工作,但它只是随机工作。
目前我从 RMI 日志中得到以下输出
Nov 04, 2019 2:56:33 PM sun.rmi.server.LoaderHandler loadClass
FEINER: RMI TCP Connection(4)-10.45.42.206: (thread context class loader: class org.jvoicexml.config.JVoiceXmlClassLoader[repo=jsapi20,...,file:/C:/Users/dwalka/Documents/git/JVoiceXML/org.jvoicexml/build/libs/org.jvoicexml-0.7.9.jar,...,parent=sun.misc.Launcher$AppClassLoader@3d4eac69])
Nov 04, 2019 2:56:33 PM sun.rmi.server.LoaderHandler loadClass
FEIN: RMI TCP Connection(4)-10.45.42.206: class "org.jvoicexml.UuidSessionIdentifer" not found via codebase
java.lang.ClassNotFoundException: org.jvoicexml.UuidSessionIdentifer
父类加载器如下所示
2019-11-04T14:56:08,505 [JVoiceXmlMain ] INFO cexml.jndi.classserver.ClassloaderServer ( 56) - parent class loader 'sun.misc.Launcher$AppClassLoader@3d4eac69'
...
2019-11-04T14:56:08,506 [JVoiceXmlMain ] INFO cexml.jndi.classserver.ClassloaderServer ( 64) - parent class loader entry: 'file:/C:/Users/dwalka/Documents/git/JVoiceXML/org.jvoicexml/build/libs/org.jvoicexml-0.7.9.jar'
...
旁注:找到来自 JDK 的类,例如 java.net.URI
jar 包含类
C:\Users\dwalka\Documents\git\JVoiceXML\org.jvoicexml\build\libs>jar -tf org.jvoicexml-0.7.9.jar | findstr "UuidSessionIdentifer"
org/jvoicexml/UuidSessionIdentifer.class
我做了一些单元测试以确保它可以正常工作(没有 RMI)。它找到类
- 在同一个罐子里
- 来自讨论中的罐子
- 来自不在 CLASSPATH 中的其他 jars
这是我的类加载器
public final class JVoiceXmlClassLoader extends URLClassLoader {
/** The repository that this class loader is responsible for. */
private final String repository;
/**
* Constructs a new object.
* @param parent the parent class loader.
*/
public JVoiceXmlClassLoader(final ClassLoader parent) {
this(parent, null);
}
/**
* Constructs a new object.
* @param parent the parent class loader.
* @param repo the repository that this class loader is responsible for
*/
public JVoiceXmlClassLoader(final ClassLoader parent, final String repo) {
super(new URL[0], parent);
repository = repo;
}
/**
* Retrieves the used repository
* @return the repository.
* @since 0.7.9
*/
public String getRepository() {
return repository;
}
/**
* {@inheritDoc}
*/
@Override
public void addURL(final URL url) {
super.addURL(url);
}
}
设置了安全管理器
"-Djava.security.manager",
"-Djava.security.policy=${project(':org.jvoicexml').buildDir}/config/jvoicexml.policy",
而且政策文件非常宽松
grant {
permission java.security.AllPermission;
};
奇怪的是,它以前可以正常工作。从那以后我所做的改变
- 切换到 Windows 10
- 与此同时,我验证了在 Linux (Ubuntu) 下也会出现同样的问题
- 更新到 Gradle 5.4.1
【问题讨论】:
标签: java classloader rmi urlclassloader