从自定义 ClassLoader 添加或删除特定的 jar
Add or remove specific jars from custom ClassLoader
我想创建 以在受控环境中执行 JSR223 脚本但失败了,
我正在尝试 remove/add 使用当前(父)类加载器的罐子,我尝试了解决方案 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);
}
}
但它没有包括我所有的罐子,在测试这个工作
ClassLoader cl = this.getClass().getClassLoader();
Class cls = cl.loadClass("org.springframework.http.HttpStatus");
但是使用解决方案没有找到class
ClassLoader cl = new DistributionClassLoader(this.getClass().getClassLoader());
Class cls = cl.loadClass("org.springframework.http.HttpStatus");
异常:
java.lang.ClassNotFoundException: org.springframework.http.HttpStatus
at com.DistributionClassLoader.loadClass(DistributionClassLoader.java:24)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
我如何select特定 jar 来添加或从 ClassLoader 中删除?
编辑
我可以使用 @czdepski answer 加载 jar,但我仍然想删除 all/most classes 除了 JDK 的
Method sysMethod = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
sysMethod.setAccessible(true);
sysMethod.invoke(sysLoader, new Object[]{url});
你弄错了代表团。如果它有这个 class.
,你永远不会检查父 class 加载器
如果我们查看 ClassLoader.loadClass(String,boolean)
的 Javadoc,我们会发现:
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
Invoke findLoadedClass(String)
to check if the class has already been loaded.
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.
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
,但没有对其父类加载器进行任何委托。
相反,您调用 classLoadersByDistribution.get(distribution.get());
,这很可能是 null
(很难说,但总是期望 WeakHashMap.get()
到 return null
)。
如果 delegate
不为空,则您尝试从那里加载 class。这意味着加载的 class 不会使用您的 ClassLoader 来加载新的 classes,而是使用您委托给的 ClassLoader。
毕竟,这听起来像 XY Problem。您想使用脚本 API 执行一些代码并以某种方式控制环境。
您是否尝试使用 SecurityManager
?
关于您的评论,您需要自己 ClassLoader
来创建 ScriptEngineManager: This ClassLoader is used to search for ScriptEngineFactory implementations. This is done using a service provider interface。
如果你不使用自己的脚本引擎,这对你来说应该无关紧要。
如果您的目标是添加几个 jar 以便引擎可以使用它,请创建一个新的 URLClassLoader
并将平台 class 加载器作为父级。 (或扩展 class 加载程序,取决于 java 版本。)
将此 ClassLoader 设置为 Thread.setContextClassLoader()
并创建 ScriptEngine.
如果您确实选择了 URLClassLoader
的父级,它将看不到 class 应用程序 class 加载程序可加载的内容。
我想创建
我正在尝试 remove/add 使用当前(父)类加载器的罐子,我尝试了解决方案 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); } }
但它没有包括我所有的罐子,在测试这个工作
ClassLoader cl = this.getClass().getClassLoader();
Class cls = cl.loadClass("org.springframework.http.HttpStatus");
但是使用解决方案没有找到class
ClassLoader cl = new DistributionClassLoader(this.getClass().getClassLoader());
Class cls = cl.loadClass("org.springframework.http.HttpStatus");
异常:
java.lang.ClassNotFoundException: org.springframework.http.HttpStatus
at com.DistributionClassLoader.loadClass(DistributionClassLoader.java:24)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
我如何select特定 jar 来添加或从 ClassLoader 中删除?
编辑
我可以使用 @czdepski answer 加载 jar,但我仍然想删除 all/most classes 除了 JDK 的
Method sysMethod = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); sysMethod.setAccessible(true); sysMethod.invoke(sysLoader, new Object[]{url});
你弄错了代表团。如果它有这个 class.
,你永远不会检查父 class 加载器如果我们查看 ClassLoader.loadClass(String,boolean)
的 Javadoc,我们会发现:
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
Invoke
findLoadedClass(String)
to check if the class has already been loaded.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.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
,但没有对其父类加载器进行任何委托。
相反,您调用 classLoadersByDistribution.get(distribution.get());
,这很可能是 null
(很难说,但总是期望 WeakHashMap.get()
到 return null
)。
如果 delegate
不为空,则您尝试从那里加载 class。这意味着加载的 class 不会使用您的 ClassLoader 来加载新的 classes,而是使用您委托给的 ClassLoader。
毕竟,这听起来像 XY Problem。您想使用脚本 API 执行一些代码并以某种方式控制环境。
您是否尝试使用 SecurityManager
?
关于您的评论,您需要自己 ClassLoader
来创建 ScriptEngineManager: This ClassLoader is used to search for ScriptEngineFactory implementations. This is done using a service provider interface。
如果你不使用自己的脚本引擎,这对你来说应该无关紧要。
如果您的目标是添加几个 jar 以便引擎可以使用它,请创建一个新的 URLClassLoader
并将平台 class 加载器作为父级。 (或扩展 class 加载程序,取决于 java 版本。)
将此 ClassLoader 设置为 Thread.setContextClassLoader()
并创建 ScriptEngine.
如果您确实选择了 URLClassLoader
的父级,它将看不到 class 应用程序 class 加载程序可加载的内容。