如何在运行时动态加载Jars?

本文翻译自:How should I load Jars dynamically at runtime?

Why is it so hard to do this in Java? 为什么用Java这么难? If you want to have any kind of module system you need to be able to load jars dynamically. 如果要使用任何类型的模块系统,则需要能够动态加载jar。 I'm told there's a way of doing it by writing your own ClassLoader , but that's a lot of work for something that should (in my mind at least) be as easy as calling a method with a jar file as its argument. 有人告诉我,有一种方法可以通过编写自己的ClassLoader ,但是对于(至少在我看来)应该像调用带有jar文件作为其参数的方法一样容易的事情来说,这是很多工作。

Any suggestions for simple code that does this? 对执行此操作的简单代码有什么建议吗?


#1楼

参考:https://stackoom.com/question/fO4/如何在运行时动态加载Jars


#2楼

How about the JCL class loader framework ? JCL类加载器框架如何? I have to admit, I haven't used it, but it looks promising. 我不得不承认,我没有使用过,但是看起来很有希望。

Usage example: 用法示例:

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");

#3楼

If you are working on Android, the following code works: 如果您使用的是Android,则以下代码适用:

String jarFile = "path/to/jarfile.jar";
DexClassLoader classLoader = new DexClassLoader(jarFile, "/data/data/" + context.getPackageName() + "/", null, getClass().getClassLoader());
Class<?> myClass = classLoader.loadClass("MyClass");

#4楼

Here is a version that is not deprecated. 这是不推荐使用的版本。 I modified the original to remove the deprecated functionality. 我修改了原始文件以删除不推荐使用的功能。

/**************************************************************************************************
 * 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();
    }
}

#5楼

The solution proposed by jodonnell is good but should be a little bit enhanced. jodonnell提出的解决方案很好,但是应该有所增强。 I used this post to develop my application with success. 我使用这篇文章成功地开发了我的应用程序。

Assign the current thread 分配当前线程

Firstly we have to add 首先,我们必须添加

Thread.currentThread().setContextClassLoader(classLoader);

or you will not able to load resource (such as spring/context.xml) stored into the jar. 否则您将无法将存储的资源(例如spring / context.xml)加载到jar中。

Do not include 不包括

your jars into the parent class loader or you will not able to understand who is loading what. 您的jar放入父类加载器,否则您将无法理解谁正在加载什么。

see also Problem reloading a jar using URLClassLoader 另请参见使用URLClassLoader重新加载jar时出现问题

However, OSGi framework remain the best way. 但是,OSGi框架仍然是最好的方法。


#6楼

With Java 9 , the answers with URLClassLoader now give an error like: 使用Java 9时URLClassLoader的答案现在会给出如下错误:

java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader

This is because the class loaders used have changed. 这是因为使用的类加载器已更改。 Instead, to add to the system class loader, you can use the Instrumentation API through an agent. 相反,要添加到系统类加载器,可以通过代理使用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: 添加META-INF / MANIFEST.MF并将其放在具有代理类的JAR文件中:

Manifest-Version: 1.0
Agent-Class: ClassPathAgent.ClassPathAgent

Run the agent: 运行代理:

This uses the byte-buddy-agent library to add the agent to the running JVM: 这使用byte-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());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值