Java动态加载jar及class文件

    经常碰到需要动态加载jar及class文件的场景。Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,但JDK仍提供了一整套方法来动态加载jar文件和class文件。

一、动态加载jar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 系统类库路径
File libPath = new File(jar文件所在路径);
 
// 获取所有的.jar和.zip文件
File[] jarFiles = libPath.listFiles(new FilenameFilter() {
    public boolean accept(File dir, String name) {
        return name.endsWith(".jar") || name.endsWith(".zip");
    }
});
 
if (jarFiles != null) {
    // 从URLClassLoader类中获取类所在文件夹的方法
    // 对于jar文件,可以理解为一个存放class文件的文件夹
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    boolean accessible = method.isAccessible();     // 获取方法的访问权限
    try {
        if (accessible == false) {
            method.setAccessible(true);     // 设置方法的访问权限
        }
        // 获取系统类加载器
        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        for (File file : jarFiles) {
            URL url = file.toURI().toURL();
            try {
                method.invoke(classLoader, url); 
                LOG.debug("读取jar文件[name={}]", file.getName());
            } catch (Exception e) {
                LOG.error("读取jar文件[name={}]失败", file.getName());
            }
        }
    } finally {
        method.setAccessible(accessible);
    }
}

 二、动态加载class文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 设置class文件所在根路径
// 例如/usr/java/classes下有一个test.App类,则/usr/java/classes即这个类的根路径,而.class文件的实际位置是/usr/java/classes/test/App.class
File clazzPath = new File(class文件所在根路径);
 
// 记录加载.class文件的数量
int clazzCount = 0;
 
if (clazzPath.exists() && clazzPath.isDirectory()) {
    // 获取路径长度
    int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;
 
    Stack<File> stack = new Stack<>();
    stack.push(clazzPath);
 
    // 遍历类路径
    while (stack.isEmpty() == false) {
        File path = stack.pop();
        File[] classFiles = path.listFiles(new FileFilter() {
            public boolean accept(File pathname) {
                return pathname.isDirectory() || pathname.getName().endsWith(".class");
            }
        });
        for (File subFile : classFiles) {
            if (subFile.isDirectory()) {
                stack.push(subFile);
            } else {
                if (clazzCount++ == 0) {
                    Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
                    boolean accessible = method.isAccessible();
                    try {
                        if (accessible == false) {
                            method.setAccessible(true);
                        }
                        // 设置类加载器
                        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
                        // 将当前类路径加入到类加载器中
                        method.invoke(classLoader, clazzPath.toURI().toURL());
                    } finally {
                        method.setAccessible(accessible);
                    }
                }
                // 文件名称
                String className = subFile.getAbsolutePath();
                className = className.substring(clazzPathLen, className.length() - 6);
                className = className.replace(File.separatorChar, '.');
                // 加载Class类
                Class.forName(className);
                LOG.debug("读取应用程序类文件[class={}]", className);
            }
        }
    }
}

 完成上述两步操作后,即可使用Class.forName来加载jar中或.class文件包含的Java类了。

posted @   moonandstar08  阅读(9013)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示