`
obullxl
  • 浏览: 182060 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

    博客分类:
  • Java
阅读更多

最近在考虑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包。

 

欢迎指正~~~~~~~ 

6
6
分享到:
评论
6 楼 xsz0606 2011-08-17  
我想问一下,为什么要使用反射这么迂回的方式,直接使用system.addURL不行吗?
5 楼 strawren 2010-07-06  
我把它改成了如下,主要用在web app里:
public class ClassLoaderUtils {
protected static Log log = LogFactory.getLog(ClassLoaderUtils.class);

private ClassLoaderUtils() {

}

public static void addURL(String url, ClassLoader classLoader) {
log.debug("addURL(),url->" + url);

if (StringUtils.isBlank(url)) {
return;
}
ClassLoader threadContextClassLoader = classLoader;
if (threadContextClassLoader == null) {
threadContextClassLoader = Thread.currentThread().getContextClassLoader();
}
boolean is = threadContextClassLoader instanceof URLClassLoader;
if (is) {
try {
URL realUrl = new URL(url);
URLClassLoader curr = (URLClassLoader) threadContextClassLoader;
Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
add.setAccessible(true);
add.invoke(curr, new Object[] { realUrl });
}
catch (Exception e) {
log.warn("WARN", e);
throw new IllegalArgumentException(e);
}
} else {
log.warn("the classloader is not a URLClassLoader type!");
throw new IllegalArgumentException("the classloader is not a URLClassLoader type!");
}
}

public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable e) {
log.info("INFO", e);
}
if (cl == null) {
cl = ClassLoaderUtils.class.getClassLoader();
}
return cl;
}
----------------
当然也可以自己通过继承URLClassLoader自己实现类加载。
4 楼 obullxl 2010-04-23  
ivywjhua 写道

看了这篇文章,升级方法值得参考,但和本文的目的有点不同。
我想做的是:升级单位是JAR包,不是一个类文件;升级下载一个JAR包后,并不是立即加载运行,而把它放在一个tmp目录,下次系统运行时再加载。
3 楼 ivywjhua 2010-04-23  
写一个  CustomizeClassloader, 继承自URLClassloader, 把addURL暴露出来
1 楼 obullxl 2010-04-23  
说明下,AppClassLoader是URLClassLoader的子类:
System.out.println(ClassLoader.getSystemClassLoader() instanceof URLClassLoader);
输出结果为:true

相关推荐

    动态加载Apk、Jar

    通过自定义ClassLoader,实现动态加载apk,jar包功能。

    掌握Java类加载器

    类加载器是Java最强大的特征之一。但是开发者常常忘记类加载组件。类加载器是在运行时负责寻找和加载类...默认状态下,应用程序的每个类由java.lang.ClassLoader加载。因为它可以被继承,所以可以自由地加强其功能。

    Java版水果管理系统源码-java-advanced:java-高级

    基于自定义Classloader实现类的动态加载和卸载:需要设计加载和卸载。 基于自定义Classloader实现模块化机制:需要设计模块化机制。 使用xar作为模块,实现xar动态加载和卸载:综合应用前面的内容。 NIO 常规 使用 ...

    Java虚拟机JVM类加载初始化

    1):本地编译好的class中直接加载 2):网络加载:java.net.URLClassLoader可以加载url指定的类 3):从jar、zip等等压缩文件加载类,自动解析jar文件找到class文件...而由用户自定义的类加载器所加载的类会被卸载掉!

    indexed-classloader:一个自定义的 JVM 类加载器,它索引类路径元素以获得更快的类资源位置

    构建: ./make-jar.sh 要使用,将indexed-classpath.jar添加到类路径并设置-Djava.system.class.loader=org.pantsbuild.classloader.IndexedURLClassLoader 。 添加-verbose:class以查看来自类加载器的调试信息。

    CustomClassLoader:Java 自定义类加载器

    类加载器 以下代码是一个自定义类加载器,它从 jar 文件加载类。

    ClassLoaderTest:测试如何正确关闭类加载器,以便可以关闭基础jar文件上的文件句柄

    ClassLoaderTest 测试自定义的URLClassLoader以加载类 测试如何正确关闭类加载器。 测试如何使用反射关闭JarFile来修复资源泄漏。

    Java发展史_&_Java9、10新特性

    主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去,模块化可以根据模块的需要加载程序运行需要的class。 在引入了模块系统之后,JDK 被重新组织成 94 ...

    JSP开发实用技术整理

    13. 自定义ClassLoader 13 14. double保留两位数的两个方案 18 16. 用户输入输出,文件输入输出范例(1) 19 17.以指定符号分割显示 22 17. 单例模式 22 18. 工厂模式 23 19. 读取配置文件(1) 25 20. 根据libName动态...

    springboot参考指南

    打包用于生产的应用程序 ix. 21. 接下来阅读什么 5. IV. Spring Boot特性 i. 22. SpringApplication i. 22.1. 自定义Banner ii. 22.2. 自定义SpringApplication iii. 22.3. 流畅的构建API iv. 22.4. Application...

    超级有影响力霸气的Java面试题大全文档

    但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微软COM模型中的本地...

    java 面试题 总结

    但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微软COM模型中的本地...

Global site tag (gtag.js) - Google Analytics