如何在Java运行的时候动态加载一个jar包到classpath里面

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Java运行的时候动态加载一个jar包到classpath里面相关的知识,希望对你有一定的参考价值。

给你个例子自己看一下吧不会了再追问,注释基本都有了
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125    import java.io.<img id="selectsearch-icon" src="https://gss0.bdstatic.com/70cFsjip0QIZ8tyhnq/img/iknow/qb/select-search.png" alt="搜索">File;import java.lang.reflect.<a href="https://www.baidu.com/s?wd=Method&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">Method</a>;import java.net.<a href="https://www.baidu.com/s?wd=URL&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank"class="baidu-highlight">URL</a>;import java.net.<a href="https://www.baidu.com/s?wd=URL&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank"class="baidu-highlight">URL</a><a href="https://www.baidu.com/s?wd=Class&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">Class</a>Loader;import java.util.List; public final <a href="https://www.baidu.com/s?wd=class&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank"class="baidu-highlight">class</a> Ext<a href="https://www.baidu.com/s?wd=Class&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">Class</a>pathLoader          private static <a href="https://www.baidu.com/s?wd=Method&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">Method</a> add<a href="https://www.baidu.com/s?wd=URL&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">URL</a> = initAdd<a href="https://www.baidu.com/s?wd=Method&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">Method</a>();     private static URLClassLoader classloader = (URLClassLoader) ClassLoader.getSystemClassLoader();     /**      * <a href="https://www.baidu.com/s?wd=%E5%88%9D%E5%A7%8B%E5%8C%96&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3ryc3nvD4mWT4rjnzmvw-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EPjRdP1mdPj6dn10dnWf3nHmd" target="_blank" class="baidu-highlight">初始化</a>addUrl 方法.     * @return 可访问addUrl方法的Method对象     */    private static Method initAddMethod()         try             Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]  URL.class );            add.setAccessible(true);            return add;                catch (Exception e)             throw new RuntimeException(e);                  /**      * 加载jar classpath。     */    public static void loadClasspath()         List<String> files = getJarFiles();        for (String f : files)             loadClasspath(f);                 List<String> resFiles = getResFiles();         for (String r : resFiles)             loadResourceDir(r);                 private static void loadClasspath(String filepath)         File file = new File(filepath);        loopFiles(file);         private static void loadResourceDir(String filepath)         File file = new File(filepath);        loopDirs(file);         /** *//**         * 循环遍历目录,找出所有的资源路径。     * @param file 当前遍历文件     */    private static void loopDirs(File file)         // 资源文件只加载路径        if (file.isDirectory())             addURL(file);            File[] tmps = file.listFiles();            for (File tmp : tmps)                 loopDirs(tmp);                             /**      * 循环遍历目录,找出所有的jar包。     * @param file 当前遍历文件     */    private static void loopFiles(File file)         if (file.isDirectory())             File[] tmps = file.listFiles();            for (File tmp : tmps)                 loopFiles(tmp);                            else             if (file.getAbsolutePath().endsWith(".jar") || file.getAbsolutePath().endsWith(".zip"))                 addURL(file);                                 /**     * 通过filepath加载文件到classpath。     * @param filePath 文件路径     * @return URL     * @throws Exception 异常     */    private static void addURL(File file)         try             addURL.invoke(classloader, new Object[]  file.toURI().toURL() );                catch (Exception e)                    /***     * 从配置文件中得到配置的需要加载到classpath里的路径集合。     * @return     */    private static List<String> getJarFiles()         // TODO 从properties文件中读取配置信息  如果不想配置 可以自己new 一个List<String> 然后把 jar的路径加进去 然后返回        return null;         /**     * 从配置文件中得到配置的需要加载classpath里的资源路径集合     * @return     */    private static List<String> getResFiles()         //TODO 从properties文件中读取配置信息略  如果不想配置 可以自己new 一个List<String> 然后把 jar的路径加进去 然后返回  额 如果没有资源路径为空就可以了        return null;         public static void main(String[] args)         ExtClasspathLoader.loadClasspath();    

参考技术A 在项目目录下创建文件夹,一般命名为lib,把你的jar包复制进入,再选择所有的jar包,右键菜单有一个Build Path,下拉菜单只有一个选择,点击就加入了

如何在模块化的 java 11 应用程序中动态加载 Libreoffice jar,而不从自定义类加载器中获取 ClassCastException

【中文标题】如何在模块化的 java 11 应用程序中动态加载 Libreoffice jar,而不从自定义类加载器中获取 ClassCastException【英文标题】:How to load Libreoffice jars dynamically in modulairzed java 11 application without getting a ClassCastException from custom class loader 【发布时间】:2019-09-08 18:00:03 【问题描述】:

我正在尝试在运行时从模块化 java 11 应用程序加载和访问 libreoffice uno jar。

为了在编译时使用 libreoffice 类并避免拆分包的问题,​​我们将所有 jar 合并到一个 single one 中,自动模块名称为 org.jabref.thirdparty.libreoffice

为了从 libreoffice 安装目录加载 jars(例如C:\Program Files\LibreOffice\program\classes 为了确保从程序文件而不是从我的模块路径加载 jars,我创建了一个自定义类加载器。

   URL[] urls = jarUrls.toArray(new URL[3]);
    Class<Bootstrap> clazz  = (Class<Bootstrap>) Class.forName("com.sun.star.comp.helper.Bootstrap", true, new ChildFirstClassLoader(urls, this.getClass().getClassLoader()));
    Boostrap boot = clazz.getDeclaredConstructor().newInstance();
    XComponentContext xContext = boot.bootstrap():

现在这给了我以下错误:

 java.lang.ClassCastException: class com.sun.star.comp.helper.Bootstrap cannot be cast to class com.sun.star.comp.helper.Bootstrap (com.sun.star.comp.helper.Bootstrap is in unnamed module of loader org.jabref.logic.openoffice.ChildFirstClassLoader @13c4b54c; com.sun.star.comp.helper.Bootstrap is in module org.jabref.thirdparty.libreoffice of loader 'app')

我确实了解这里的问题并阅读了很多关于此的内容,但找不到解决此问题的方法。关键问题是我必须使用 LO 文件夹中的 jar,否则它将找不到 libreoffice 实例。我也想过将模块化的 jar 放入 LO 文件夹中,但不确定这是否可行。

在 Java 8 下,我们使用典型的“反射 + addUrls”方法,因为所有内容都在类路径中。

这是自定义类加载器:

public class ChildFirstClassLoader extends URLClassLoader 

    public ChildFirstClassLoader(URL[] urls, ClassLoader parent) 
        super(urls, parent);
    

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException 
        // has the class loaded already?
        Class<?> loadedClass = findLoadedClass(name);
        if (loadedClass == null) 
            try 
                // find the class from given jar urls 
                loadedClass = findClass(name);
             catch (ClassNotFoundException e) 
                // Hmmm... class does not exist in the given urls.
                // Let's try finding it in our parent classloader.
                // this'll throw ClassNotFoundException in failure.                  
                loadedClass = super.loadClass(name, resolve);
            
        
        if (resolve)  // marked to resolve
            resolveClass(loadedClass);
        
        return loadedClass;
    

【问题讨论】:

【参考方案1】:

从 LibreOffice 7.0 开始,现在有一个与 Java 模块系统一起使用的组合 libreoffice.jar。

【讨论】:

以上是关于如何在Java运行的时候动态加载一个jar包到classpath里面的主要内容,如果未能解决你的问题,请参考以下文章

java可以动态加载一个jar包,并且调用里面的类和方法吗?

在加载类时,如何指定所使用的jar包

请教如何在linux下部署java项目同时引入其他jar包,然后执行java项目的main函数的操作

如何将spring boot工程打成JAR包到服务器上运行

如何在模块化的 java 11 应用程序中动态加载 Libreoffice jar,而不从自定义类加载器中获取 ClassCastException

maven引用遗留项目的jar文件:上传任意一个jar 包到maven 仓库