为什么在Java中这么难做到这一点?如果您希望拥有任何类型的模块系统,您需要能够动态加载JAR文件。有人告诉我,有一种方法可以通过编写自己的ClassLoader来实现,但这需要做很多工作,因为(至少在我看来)应该像调用以JAR文件作为参数的方法一样简单。
对实现这一功能的简单代码有什么建议吗?
为什么在Java中这么难做到这一点?如果您希望拥有任何类型的模块系统,您需要能够动态加载JAR文件。有人告诉我,有一种方法可以通过编写自己的ClassLoader来实现,但这需要做很多工作,因为(至少在我看来)应该像调用以JAR文件作为参数的方法一样简单。
对实现这一功能的简单代码有什么建议吗?
当前回答
这可能是一个延迟响应,我可以这样做(fastutil-8.2.2.jar的一个简单示例)使用jhplot。来自DataMelt的Web类(http://jwork.org/dmelt)
import jhplot.Web;
Web.load("http://central.maven.org/maven2/it/unimi/dsi/fastutil/8.2.2/fastutil-8.2.2.jar"); // now you can start using this library
根据文档,这个文件将在“lib/user”中下载,然后动态加载,因此您可以立即在同一个程序中使用这个jar文件中的类。
其他回答
你应该看一看OSGi,比如在Eclipse平台中实现的。它就是这么做的。您可以安装、卸载、启动和停止所谓的包,这些包实际上是JAR文件。但是它做的更多,例如,它提供了可以在运行时在JAR文件中动态发现的服务。
或参阅Java模块系统的规范。
对于jar文件的动态上传,您可以使用我对URLClassLoader的修改。这种修改对于在应用程序操作期间更改jar文件没有问题,就像标准的URLClassloader一样。所有加载的jar文件都加载到RAM中,因此独立于原始文件。
内存中的jar和JDBC类装入器
在Java 9中,URLClassLoader的答案现在会给出如下错误:
java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
这是因为所使用的类装入器发生了变化。相反,要添加到系统类装入器,您可以通过代理使用Instrumentation API。
创建代理类:
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));
}
}
添加meta - inf / MANIFEST。MF并将其与代理类一起放在JAR文件中:
Manifest-Version: 1.0
Agent-Class: ClassPathAgent.ClassPathAgent
运行代理:
使用bytes -buddy-agent库将代理添加到运行的JVM中:
import java.io.File;
import net.bytebuddy.agent.ByteBuddyAgent;
public class ClassPathUtil {
private static File AGENT_JAR = new File("/path/to/agent.jar");
public static void addJarToClassPath(File jarFile) {
ByteBuddyAgent.attach(AGENT_JAR, String.valueOf(ProcessHandle.current().pid()), jarFile.getPath());
}
}
我个人认为java.util.ServiceLoader做得很好。你可以在这里得到一个例子。
JCL类装入器框架怎么样?我必须承认,我还没有用过,但它看起来很有前途。
使用的例子:
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");