JarClassLoader jcl = new JarClassLoader();
jcl.add("myjar.jar"); // Load jar file
jcl.add(new URL("http://myserver.com/myjar.jar")); // Load jar from a URL
jcl.add(new FileInputStream("myotherjar.jar")); // Load jar file from stream
jcl.add("myclassfolder/"); // Load class folder
jcl.add("myjarlib/"); // Recursively load all jar files in the folder/sub-folder(s)
JclObjectFactory factory = JclObjectFactory.getInstance();
// Create object of loaded class
Object obj = factory.create(jcl, "mypackage.MyClass");
/**************************************************************************************************
* Copyright (c) 2004, Federal University of So Carlos *
* *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted *
* provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of *
* conditions and the following disclaimer. *
* * Redistributions in binary form must reproduce the above copyright notice, this list of *
* * conditions and the following disclaimer in the documentation and/or other materials *
* * provided with the distribution. *
* * Neither the name of the Federal University of So Carlos nor the names of its *
* * contributors may be used to endorse or promote products derived from this software *
* * without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR *
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
**************************************************************************************************/
/*
* Created on Oct 6, 2004
*/
package tools;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Useful class for dynamically changing the classpath, adding classes during runtime.
*/
public class ClasspathHacker {
/**
* Parameters of the method to add an URL to the System classes.
*/
private static final Class<?>[] parameters = new Class[]{URL.class};
/**
* Adds a file to the classpath.
* @param s a String pointing to the file
* @throws IOException
*/
public static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}
/**
* Adds a file to the classpath
* @param f the file to be added
* @throws IOException
*/
public static void addFile(File f) throws IOException {
addURL(f.toURI().toURL());
}
/**
* Adds the content pointed by the URL to the classpath.
* @param u the URL pointing to the content to be added
* @throws IOException
*/
public static void addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Class<?> sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL",parameters);
method.setAccessible(true);
method.invoke(sysloader,new Object[]{ u });
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}
}
public static void main(String args[]) throws IOException, SecurityException, ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
addFile("C:\\dynamicloading.jar");
Constructor<?> cs = ClassLoader.getSystemClassLoader().loadClass("test.DymamicLoadingTest").getConstructor(String.class);
DymamicLoadingTest instance = (DymamicLoadingTest)cs.newInstance();
instance.test();
}
}
48
使用 Java 9 , URLClassLoader 的答案现在给出如下错误:
java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
这是因为使用的类加载器已经改变 . 相反,要添加到系统类加载器,可以通过代理使用Instrumentation API .
Create an agent class:
package ClassPathAgent;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;
public class ClassPathAgent {
public static void agentmain(String args, Instrumentation instrumentation) throws IOException {
instrumentation.appendToSystemClassLoaderSearch(new JarFile(args));
}
}
Add META-INF/MANIFEST.MF and put it in a JAR file with the agent class:
15 回答
JCL class loader framework怎么样?我不得不承认,我没有使用它,但看起来很有希望 .
用法示例:
安全的原因很难 . 类加载器意味着不可变;你不应该在运行时不断添加类 . 我真的很惊讶它与系统类加载器一起工作 . 以下是制作自己的子类加载器的方法:
痛苦,但它确实存在 .
以下解决方案是hackish,因为它使用反射来绕过封装,但它完美无缺:
你应该看看OSGi,例如在Eclipse Platform实施 . 它正是如此 . 您可以安装,卸载,启动和停止所谓的捆绑包,这些捆绑包实际上是JAR文件 . 但它提供了更多,因为它提供了例如可以在运行时在JAR文件中动态发现的服务 .
或者参见Java Module System的规范 .
这是一个未弃用的版本 . 我修改了原始文件以删除已弃用的功能 .
使用 Java 9 ,
URLClassLoader
的答案现在给出如下错误:这是因为使用的类加载器已经改变 . 相反,要添加到系统类加载器,可以通过代理使用Instrumentation API .
Create an agent class:
Add META-INF/MANIFEST.MF and put it in a JAR file with the agent class:
Run the agent:
这使用byte-buddy-agent库将代理添加到正在运行的JVM:
我找到的最好的是org.apache.xbean.classloader.JarFileClassLoader,这是XBean项目的一部分 .
这是我过去使用的一个简短方法,用于从特定目录中的所有lib文件创建类加载器
然后使用类加载器,只需:
如果您正在使用Android,则以下代码有效:
jodonnell提出的解决方案很好,但应该稍微增强一点 . 我用这篇文章成功开发了我的应用程序 .
分配当前线程
首先我们要补充一下
或者你将无法加载存储在jar中的资源(例如spring / context.xml) .
不包括
你的jar进入父类加载器,否则你将无法理解谁正在加载什么 .
另见Problem reloading a jar using URLClassLoader
但是,OSGi框架仍然是最好的方法 .
Allain的另一个hackish解决方案版本,也适用于JDK 11:
在JDK 11上,它提供了一些弃用警告,但作为在JDK 11上使用Allain解决方案的人的临时解决方案 .
使用Instrumentation的另一个工作解决方案适用于我 . 它具有修改类加载器搜索的优点,避免了依赖类的类可见性问题:
Create an Agent Class
对于此示例,它必须位于命令行调用的同一jar上:
Modify the MANIFEST.MF
添加对代理的引用:
我实际上使用Netbeans,所以this post有助于如何更改manifest.mf
Running
Launcher-Agent-Class
仅在JDK 9上受支持,并且负责加载代理而不在命令行上显式定义它:适用于JDK 6的方法是定义
-javaagent
参数:Adding new Jar at Runtime
然后,您可以使用以下命令根据需要添加jar:
我在文档中没有发现任何问题 .
以下是Allain方法的快速解决方法,使其与更新版本的Java兼容:
请注意,它依赖于特定JVM内部实现的知识,因此它并不理想,并且它不是通用的解决方案 . 但如果您知道要使用标准OpenJDK或Oracle JVM,那么这是一种快速简便的解决方法 . 在将来发布新的JVM版本时,它可能会在某些时候中断,因此您需要牢记这一点 .
请看看我开始的这个项目:proxy-object lib
此lib将从文件系统或任何其他位置加载jar . 它将为jar专用一个类加载器,以确保没有库冲突 . 用户将能够从加载的jar中创建任何对象并调用其上的任何方法 . 此lib旨在从支持Java 7的代码库加载在Java 8中编译的jar .
要创建对象:
ObjectBuilder支持工厂方法,调用静态函数和回调接口实现 . 我将在自述页面上发布更多示例 .
这可能是一个迟到的响应,我可以使用DataMelt的jhplot.Web类(这是一个简单的fastutil-8.2.2.jar示例)(http://jwork.org/dmelt)
根据文档,此文件将在“lib / user”中下载,然后动态加载,因此您可以立即开始使用同一程序中此jar文件中的类 .
我个人觉得java.util.ServiceLoader做得很好 . 你可以得到一个例子here .