gpt4 book ai didi

java - 从自定义类加载器中添加或删除特定的 jar

转载 作者:行者123 更新时间:2023-12-02 09:42:28 28 4
gpt4 key购买 nike

我想创建dynamically a classloader用于在受控环境中执行 JSR223 脚本但失败,

我正在尝试使用当前(父)类加载器删除/添加 jar,我尝试了解决方案 Dynamically removing jars from classpath

public class DistributionClassLoader extends ClassLoader {
public DistributionClassLoader(ClassLoader parent) {
super(parent);
}
private Map<String, ClassLoader> classLoadersByDistribution =
Collections.synchronizedMap(new WeakHashMap<>());
private final AtomicReference<String> distribution = new AtomicReference<>();
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
final ClassLoader delegate = classLoadersByDistribution.get(distribution.get());
if (delegate != null) return Class.forName(name, true, delegate);
throw new ClassNotFoundException(name);
}
public void addDistribution(String key, ClassLoader distributionClassLoader){
classLoadersByDistribution.put(key,distributionClassLoader);
}
public void makeDistributionActive(String key){distribution.set(key);}
public void removeDistribution(String key){
final ClassLoader toRemove = classLoadersByDistribution.remove(key);
}
}

但它不包括我所有的 jar ,在测试这项工作

ClassLoader cl = this.getClass().getClassLoader();
Class cls = cl.loadClass("org.springframework.http.HttpStatus");

但是使用解决方案找不到类

ClassLoader cl = new DistributionClassLoader(this.getClass().getClassLoader());
Class cls = cl.loadClass("org.springframework.http.HttpStatus");

异常(exception):

java.lang.ClassNotFoundException: org.springframework.http.HttpStatus
at com.DistributionClassLoader.loadClass(DistributionClassLoader.java:24)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

如何选择要从 ClassLoader 添加或删除的特定 jar?

编辑

我可以使用 @czdepski answer 加载 jars但我仍然想删除除 JDK 之外的所有/大多数类

Method sysMethod = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
sysMethod.setAccessible(true);
sysMethod.invoke(sysLoader, new Object[]{url});

最佳答案

你把委托(delegate)弄错了。您永远不会检查父类加载器是否有此类。

如果我们看一下Javadoc对于 ClassLoader.loadClass(String,boolean) 我们发现:

Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:

  1. Invoke findLoadedClass(String) to check if the class has already been loaded.

  2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built into the virtual machine is used, instead.

  3. Invoke the findClass(String) method to find the class.

If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.

Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method.

您确实重写了 loadClass,但没有对其父类加载器进行任何委托(delegate)。
相反,您调用 classLoadersByDistribution.get(distribution.get());,这很可能是 null (很难说,但总是期望 WeakHashMap.get() 返回null)。

如果delegate不为空,那么您尝试从那里加载该类。这意味着加载的类不会使用您的 ClassLoader 来加载新类,而是使用您委托(delegate)给的 ClassLoader。

毕竟,这听起来像 XY Problem 。您想要使用脚本 API 执行一些代码并以某种方式控制环境。
您是否尝试过使用SecurityManager

<小时/>

关于您的评论,您需要自己的ClassLoader来创建ScriptEngineManager :该类加载器用于搜索 ScriptEngineFactory 实现。这是使用 service provider interface 完成的.
如果您不使用自己的脚本引擎,这对您来说应该不重要。

<小时/>

如果您的目标是添加一些 jar 以便引擎可以使用它,请创建一个新的 URLClassLoader 并将平台类加载器作为父级。 (或扩展类加载器,取决于java版本。)
将此类加载器设置为 Thread.setContextClassLoader() 并创建 ScriptEngine。

如果您正确选择了 URLClassLoader 的父级,它将看不到应用程序类加载器可加载的类。

关于java - 从自定义类加载器中添加或删除特定的 jar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56964633/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com