自定义ClassLoader,用于加载用户JAR包

未分类 一条评论

最近在考虑C/S结构程序的软件自动升级的实现方式,比如QQ、飞信等都自动升级的功能。

 

自动升级模块虽然还没有编码完成,但是思路还是比较清晰的。

 

自动升级过程中,升级文件的JAR包是专门加载到程序中去的,因此,自定义一个ClassLoader,用于加载用户JAR包,就非常的重要了。

 

应用程序ClassLoader只提供了一个public Class<?> loadClass(String name) throws ClassNotFoundException 方法,没有提供加载JAR的方法。

 

URLClassLoader提供了一个protected void addURL(URL url)的方法,倒是可以加载JAR包,但苦于非public的。

 

经测试发现,AppClassLoader是URLClassLoader的子类。因此,我们完全可以利用URLClassLoader了哦。

URLClassLoader system = (URLClassLoader) ClassLoader.getSystemClassLoader();

 

这样,我们可以通过反射得到addURL方法,在程序中加载我们自己的JAR包了。

 

整个源代码如下所示:

/**
 * Copyright (c) YMCN Team
 * All rights reserved.
 */
package com.aboy.toolkit.util;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

/**
 * @author obullxl
 *
 * email: obullxl@163.com  MSN: obullxl@hotmail.com  QQ: 303630027
 *
 * Blog: http://obullxl.iteye.com
 */
public final class ClassLoaderUtil {
    /** URLClassLoader的addURL方法 */
    private static Method addURL = initAddMethod();
    
    /** 初始化方法 */
    private static final Method initAddMethod() {
        try {
            Method add = URLClassLoader.class
                .getDeclaredMethod("addURL", new Class[] { URL.class });
            add.setAccessible(true);
            return add;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static URLClassLoader system = (URLClassLoader) ClassLoader.getSystemClassLoader();

    /**
     * 循环遍历目录,找出所有的JAR包
     */
    private static final void loopFiles(File file, List<File> files) {
        if (file.isDirectory()) {
            File[] tmps = file.listFiles();
            for (File tmp : tmps) {
                loopFiles(tmp, files);
            }
        } else {
            if (file.getAbsolutePath().endsWith(".jar") || file.getAbsolutePath().endsWith(".zip")) {
                files.add(file);
            }
        }
    }

    /**
     * <pre>
     * 加载JAR文件
     * </pre>
     *
     * @param file
     */
    public static final void loadJarFile(File file) {
        try {
            addURL.invoke(system, new Object[] { file.toURI().toURL() });
            System.out.println("加载JAR包:" + file.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * <pre>
     * 从一个目录加载所有JAR文件
     * </pre>
     *
     * @param path
     */
    public static final void loadJarPath(String path) {
        List<File> files = new ArrayList<File>();
        File lib = new File(path);
        loopFiles(lib, files);
        for (File file : files) {
            loadJarFile(file);
        }
    }
}

 

在程序中,只要使用上面最后两个方法,就可以加载自定义JAR包和一个目录中的所有JAR包了。

 

经本人测试,上面代码运行无误,能正常加载自定义JAR包。

 

欢迎指正~~~~~~~ 

1条评论

A
AIU says: 回复

您好 请问一下addURL 对后续的加载有什么帮助吗? 源码里看到URLClassPath 中的path增加了自己的jar的path,
但是我在加载类的时候 没有代码访问过这个path的变量

发表评论

邮箱地址不会被公开。 必填项已用*标注

昵称 *