`
obullxl
  • 浏览: 183228 次
  • 性别: 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

相关推荐

    定义ClassLoader调用外部jar包

    当我们需要从外部jar包动态加载类时,自定义ClassLoader就显得尤为关键。这篇博文"定义ClassLoader调用外部jar包"探讨了如何创建一个自定义的ClassLoader,以便能够灵活地加载不在应用主类路径(ClassPath)中的jar...

    自定义classloader的使用

    自定义Classloader可以用于加载经过加密的类文件。在加载前,我们可以先解密字节码,然后传递给`defineClass`方法。这样,即使原始的类文件被窃取,没有正确的解密算法也无法运行。 五、隔离环境 在多版本库共存的...

    Java URLClassLoader动态加载jar包1

    然后,使用`Class.forName()`方法,指定了要加载的类全名(包括包名)"org.javaweb.url.Url",并传入`URLClassLoader`实例作为上下文类加载器,这样就可以确保这个类是由这个特定的`URLClassLoader`加载的。...

    动态加载jar包

    在Java中,动态加载jar包的核心在于使用`java.lang.ClassLoader`类或其子类。ClassLoader是Java虚拟机(JVM)的一部分,负责将类的字节码加载到JVM中并转换为Class对象。默认情况下,JVM会使用系统类加载器来查找和...

    ClassLoader类加载机制和原理详解

    双亲委派模型使得系统类(如java.*开头的类)由Bootstrap ClassLoader加载,而用户自定义类由应用程序类加载器(AppClassLoader)加载。这避免了类的冲突,保持了系统类库的稳定性。但有时我们可能需要打破这种模型...

    使用classloader动态加载Class

    1. **自定义ClassLoader**:Java允许我们创建自定义的ClassLoader,这通常用于实现动态加载类的需求。自定义ClassLoader需要重写`findClass()`或`loadClass()`方法。`loadClass()`方法是类加载的入口,它会调用`find...

    Java加载。jar包

    ### Java加载.jar包详解 #### 一、Java 类加载机制概览 自 JDK 1.2 版本之后,Java 类加载机制发生了一个重要的变化,引入了一种名为**类加载委托**的概念。这一机制的核心思想在于,如果某个 `ClassLoader` 无法...

    java 动态加载jar包

    在动态加载jar包的场景下,可能涉及的是服务器端接收用户请求后,根据请求内容动态加载和执行相应的插件服务。这需要一个解析请求的机制,根据请求参数找到对应的插件并调用其提供的服务。 总之,Java动态加载jar包...

    java自定义类加载classloader文档,包括代码

    1. **Bootstrap Class Loader(启动类加载器)**:该类加载器使用C++编写,是JVM自身的一部分,用于加载位于`JAVA_HOME/jre/lib/rt.jar`中的类库,以及其他一些核心类库(如`java.lang.*`等)。Bootstrap Class ...

    ClassLoader运行机制 自己写的

    这里我们将详细讨论ClassLoader的运行机制,特别是自定义ClassLoader的设计与实现。 ClassLoader的基本职责是根据类名动态加载对应的类文件。在Java中,类加载过程遵循双亲委派模型(Parent Delegation Model)。这...

    动态加载jar包的实现

    总结来说,动态加载jar包是通过自定义类加载器实现的,它使得在运行时能加载新的或更新的类,而无需重启服务。这种能力对于持续部署和热修复等场景具有极大的价值。`CSClassLoaderUtil`是这样的类加载器的一个实例,...

    jar包隔离代码.zip

    1. ClassLoader隔离:通过自定义ClassLoader,为每个模块加载特定版本的jar包,确保各模块间的类加载互不影响。 2. OSGi(Open Service Gateway Initiative)框架:OSGi提供了模块化系统,允许在同一JVM中动态加载和...

    动态加载Apk、Jar

    加载Jar包的过程与Apk类似,但相对简单,因为Jar包通常只包含Java类,没有资源和AndroidManifest.xml等。只需替换DexFile的操作,直接指定jar文件路径即可。 **标签关键词解释** - **ClassLoader**:Java中的类...

    classloader

    2. Extension ClassLoader:扩展类加载器负责加载Android系统库(如dalvik/libcore.jar和dalvik/optional.jar)之外的扩展类库,这些库位于/system/framework/extra目录下。 3. App ClassLoader:应用程序类加载器...

    java 类从哪个jar包加载的

    Bootstrap ClassLoader负责加载JRE核心库(如rt.jar),Extension ClassLoader负责加载JRE扩展目录下的JAR包,而App ClassLoader则加载应用程序的CLASSPATH中的类和JAR包。 当JVM需要加载一个类时,它会委托给合适...

    java命令执行jar包的多种方法(四种方法)

    在使用自定义 Classloader 加载 JAR 包时,我们需要实现一个自定义的 Classloader 类,并在其中加载要加载的 JAR 包。这种方法比较复杂,需要专门的讨论。 以上四种方法都可以用来执行 JAR 包,但是它们有不同的...

    JAVA动态加载JAR zip包

    总结来说,Java动态加载JAR或ZIP包是通过自定义类加载器实现的,它可以让我们在运行时按需加载外部库,提高系统的可扩展性和灵活性。这个过程涉及到类加载器的创建、文件的读取、类的解析和实例化等多个步骤,是一项...

    自定义Java类加载器

    2. **Extension ClassLoader**:扩展类加载器,负责加载`&lt;JAVA_HOME&gt;\lib\ext`目录下的JAR包,或者被`-Djava.ext.dirs`指定的路径中的类。 3. **System ClassLoader**:也称为应用类加载器,负责加载`CLASSPATH`...

    使用自定义ClassLoader解决反序列化serialVesionUID不一致问题 _ 回忆飘如雪1

    - **取消双亲委派模型**:改为当前`ClassLoader`优先加载,这样可以避免不一致的JAR被父`ClassLoader`加载,从而实现隔离。 - **便捷地共享依赖**:允许共享那些没有`serialVersionUID`冲突的类库,提高效率。 - **...

Global site tag (gtag.js) - Google Analytics