编辑:更新以回应Ani B.
编辑2:添加了更新的PluginSecurityManager.
我的应用程序有一个插件机制,第三方可以提供包含实现特定接口的类的JAR.使用URLClassLoader,我能够加载该类并实例化它,没问题.因为代码可能不受信任,我需要防止它行为不端.例如,我在一个单独的线程中运行插件代码,这样如果它进入无限循环或者只是花费太长时间我就可以杀死它.但是尝试为他们设置一个安全沙箱,以便他们无法做出像网络连接或访问硬盘驱动器上的文件这样的事情让我感到非常沮丧.我的努力总是导致对插件没有影响(它具有与应用程序相同的权限)或者也限制了应用程序.我希望主应用程序代码能够完成它想要的任何东西,
关于这一主题的文献和在线资源是复杂,混乱和矛盾的.我已经阅读过各种各样的地方(例如这个问题),我需要提供一个自定义的SecurityManager,但是当我尝试它时,我遇到了问题,因为JVM延迟加载JAR中的类.所以我可以很好地实例化它,但是如果我在加载的对象上调用一个方法来实例化来自同一个JAR的另一个类,那么它就会爆炸,因为它被拒绝了从JAR读取的权利.
从理论上讲,我可以在SecurityManager中检查FilePermission,看看它是否正在尝试加载自己的JAR.这没关系,但URLClassLoader文档说:"默认情况下,加载的类只被授予访问创建URLClassLoader时指定的URL的权限." 那为什么我甚至需要一个自定义的SecurityManager?URLClassLoader不应该只处理这个吗?为什么不呢?
这是一个重现问题的简化示例:
package test.app;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import test.api.Plugin;
public class PluginTest {
public static void pluginTest(String pathToJar) {
try {
File file = new File(pathToJar);
URL url = file.toURI().toURL();
URLClassLoader cl = new URLClassLoader(new java.net.URL[] { url });
Class<?> clazz = cl.loadClass("test.plugin.MyPlugin");
final Plugin plugin = (Plugin) clazz.newInstance();
PluginThread thread = new PluginThread(new Runnable() {
@Override
public void run() {
plugin.go();
}
}); …Run Code Online (Sandbox Code Playgroud) java -classpath ../classes;../jar;. parserTester
Run Code Online (Sandbox Code Playgroud)
如何以编程方式获取上述命令中的功能?喜欢,是否可以运行:
java parserTester
Run Code Online (Sandbox Code Playgroud)
得到相同的结果?我尝试使用URLClassLoader但它修改了类路径并且没有添加它.
感谢名单!
感谢Milhous的回应.但这就是我想要做的事情.如何才能首先将jar放入类路径?我也试过使用自定义类加载器:(
这工作..但抱歉,我只需要运行它:java parserTester我想知道这样的事情是否可能???
它需要是如此bcoz我有一个单独的文件夹中的parserTester.java和.class.我需要保留文件结构.parserTester在单独的jar文件夹中使用jar.
我需要为应用程序的某些部分添加插件功能到现有应用程序.我希望能够在运行时添加一个jar,应用程序应该能够从jar加载一个类而无需重新启动应用程序.到现在为止还挺好.我使用URLClassLoader在线发现了一些样本,它工作正常.
我还希望能够在jar的更新版本可用时重新加载同一个类.我再次找到了一些示例和实现这一点的关键,据我所知,我需要为每个新加载使用一个新的类加载器实例.
我写了一些示例代码但是遇到了NullPointerException.首先让我告诉你们代码:
package test.misc;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import plugin.misc.IPlugin;
public class TestJarLoading {
public static void main(String[] args) {
IPlugin plugin = null;
while(true) {
try {
File file = new File("C:\\plugins\\test.jar");
String classToLoad = "jartest.TestPlugin";
URL jarUrl = new URL("jar", "","file:" + file.getAbsolutePath()+"!/");
URLClassLoader cl = new URLClassLoader(new URL[] {jarUrl}, TestJarLoading.class.getClassLoader());
Class loadedClass = cl.loadClass(classToLoad);
plugin = (IPlugin) loadedClass.newInstance();
plugin.doProc();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
Thread.sleep(30000);
} catch (InterruptedException …Run Code Online (Sandbox Code Playgroud) 我们正在寻找Java web start的替代方案,它可以有效地执行相同的操作,只是更好地实现.我们遇到了大麻烦.我们有一些XP桌面办公室,所有办公室都略有不同,到目前为止只有少数办公室没有认真调整.问题与不能很好地使用代理设置(使用Java控制面板中的直接连接允许它工作),拒绝在设置"-Xmx"之类的参数时运行但在不运行时运行正常(直到它运行内存不足)和其他我们无法解决的奇怪问题.
Web开始工作的方式正是我们想要的,即连接到具有应用程序的服务器,下载任何已更改的内容,保留jar缓存等.其他团队在这里使用'clickonce'作为他们的C#应用程序,它确实有效地同样的事情,但似乎没那么麻烦.
我确信我们并不是唯一遇到这种情况的人,但搜索并没有真正显示任何替代方案.我们已经考虑编写一个存根本地应用程序,它本质上只是一个URLClassLoader,它可以动态地通过网络加载我们的应用程序,但不幸的是,它与其他办公室相比太慢了.有人有主意吗?
谢谢
更新
如果有人对最终发生的事情感到好奇,我们在一个月左右的时间里给了webstart但是继续遇到问题所以我们实现了自己的版本.它基本上只是一个存根,它有一个指向Web服务器的URL类加载器.这是<200行代码,它已经运行了好几个月.这不是理想的,但在有人改进webstart之前我们会坚持下去.
更新2018年
所以,几年后,我正在研究一个同样问题的新项目.这次我们使用的是getdown,而不是编写我们自己的webstart实现.我们发现这是对网络开始的巨大改进,它对我们来说非常好.
直到java9在运行时通过编程方式将所有人使用的外部jar添加到类路径:
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});
Run Code Online (Sandbox Code Playgroud)
现在用java9我们有问题:
线程"main"中的异常java.lang.ClassCastException:java.base/jdk.internal.loader.ClassLoaders $ AppClassLoader无法强制转换为java.base/java.net.URLClassLoader
URLClassLoader 在Java 9中不再有效.在jdk9下如何以编程方式在运行时向类路径添加外部jar?
我有一个案例,我需要在我的应用程序中创建许多类加载器,以便在用户提供的脚本运行时暂时显示一些代码.我正在使用URLClassLoader它,它的效果非常好.
当脚本终止时,我想"卸载"或"关闭"类加载器以释放资源.
是否足以将类加载器的引用设置为null?我特别想知道我是否最终会用完文件句柄,因为额外的类在JAR文件中.
PS:必须使用Java 5及更高版本.是的,我知道...
我们目前正在研究在我们的应用程序中使用OneJar(由于多种原因),但我们的应用程序使用了许多自定义URLClassloader来加载应用程序扩展.
当捆绑为"OneJar"Jar时,我们会遇到ClassNotFound异常.有问题的类存在于捆绑的Jar中,我们只是依靠类加载器机制来解析父/子关系.
那是.我们有一个共同interface的存储在捆绑的Jar中(应该在父类的类加载器上下文中).扩展实现了这一点interface(允许我们调用扩展)并依赖子类加载器使用父类加载器的资源查找功能的能力.
是否有任何人对此有任何经验或对我们如何解决它有任何启示.
我很想在其它类似机制(捆绑我们的库JAR的到一个JAR资源,不需要使用一切,罐其unjar成一个单一的文件)
下面的代码将jar文件添加到构建路径,它适用于Java 8.但是,它会抛出Java 9的异常,该异常与转换为URLClassLoader有关.有什么想法可以解决这个问题吗?最佳解决方案将对其进行编辑以与Java 8和9一起使用.
private static int AddtoBuildPath(File f) {
try {
URI u = f.toURI();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader, u.toURL());
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex) {
return 1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 安装后jdk9我一直看到这个问题:
$hive
Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hive/2.3.1/libexec/lib/log4j-slf4j-impl-2.6.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hadoop/2.8.1/libexec/share/hadoop/common/lib/slf4j-log4j12-1.7.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Exception in thread "main" java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
at org.apache.hadoop.hive.ql.session.SessionState.<init>(SessionState.java:394)
at org.apache.hadoop.hive.ql.session.SessionState.<init>(SessionState.java:370)
at org.apache.hadoop.hive.cli.CliSessionState.<init>(CliSessionState.java:60)
at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:708)
at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:686)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.apache.hadoop.util.RunJar.run(RunJar.java:234) …Run Code Online (Sandbox Code Playgroud) java ×10
urlclassloader ×10
classloader ×3
java-9 ×3
classpath ×2
class ×1
deployment ×1
dynamic ×1
hive ×1
jar ×1
onejar ×1