首页 > 基础资料 博客日记

Java运行时加载外部Jar包(class文件)

2024-06-20 22:00:06基础资料围观363

这篇文章介绍了Java运行时加载外部Jar包(class文件),分享给大家做个参考,收藏Java资料网收获更多编程知识

一、应用场景

我们在开发普通的Java业务系统时,都是正常的编译、打包、加载启动。但是在一些平台类、工具类的系统,需要支持外部插件式,以及轻量规则引擎动态加载外部业务规则等功能。

运行时加载外部Jar包(class文件),是其中一种技术解决方案,该方式广泛使用在各种主流开源组件,让开源社区其他开发者,扩展更多的功能或数据库等中间件对接。

二、URLClassLoader介绍

URLClassLoader可以从指定的URL路径中加载类资源,而不局限于传统的类路径,这些URL可以是文件系统路径、网络路径或者JAR文件路径等。这意味着可以从远程服务器或者动态生成的路径加载类文件,实现动态加载类,从而实现插件化或者动态扩展的功能。

import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;

public class Main {
    public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 定义URL数组,指定要加载的类路径
        URL[] urls = new URL[]{new URL("file:/path/to/classes/")};
        // 创建URLClassLoader实例
        URLClassLoader classLoader = new URLClassLoader(urls);

        /**
        使用jar包方式加载
        URLClassLoader classLoader = new URLClassLoader(new URL[] { new File("path/to/your.jar").toURI().toURL() });
        */
        
        // 使用URLClassLoader加载指定类
        Class<?> clazz = classLoader.loadClass("com.example.MyClass");
        
        // 实例化类对象
        Object instance = clazz.newInstance();
        
        // TODO: 使用加载的类对象进行操作
    }
}

可以看到,URLClassLoader每次初始化,都需要对jar包或class文件进行加载,这会非常消耗机器CPU性能,调用loadClass,同样会消耗CPU性能,因此在高并发的业务系统中,需要对ClassLoader以及加载后的class进行本地缓存。需要做好刷新、控制这个缓存,或做好版本的控制。

三、应用示例

以下代码截取自DataX源码(阿里巴巴开源的数据同步工具)

import com.alibaba.datax.common.exception.DataXException;
import com.alibaba.datax.core.util.FrameworkErrorCode;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

/**
 * 提供Jar隔离的加载机制,会把传入的路径、及其子路径、以及路径中的jar文件加入到class path。
 */
public class JarLoader extends URLClassLoader {
    public JarLoader(String[] paths) {
        this(paths, JarLoader.class.getClassLoader());
    }

    public JarLoader(String[] paths, ClassLoader parent) {
        super(getURLs(paths), parent);
    }

    private static URL[] getURLs(String[] paths) {
        Validate.isTrue(null != paths && 0 != paths.length,
                "jar包路径不能为空.");

        List<String> dirs = new ArrayList<String>();
        for (String path : paths) {
            dirs.add(path);
            JarLoader.collectDirs(path, dirs);
        }

        List<URL> urls = new ArrayList<URL>();
        for (String path : dirs) {
            urls.addAll(doGetURLs(path));
        }

        return urls.toArray(new URL[0]);
    }

    private static void collectDirs(String path, List<String> collector) {
        if (null == path || StringUtils.isBlank(path)) {
            return;
        }

        File current = new File(path);
        if (!current.exists() || !current.isDirectory()) {
            return;
        }

        for (File child : current.listFiles()) {
            if (!child.isDirectory()) {
                continue;
            }

            collector.add(child.getAbsolutePath());
            collectDirs(child.getAbsolutePath(), collector);
        }
    }

    private static List<URL> doGetURLs(final String path) {
        Validate.isTrue(!StringUtils.isBlank(path), "jar包路径不能为空.");

        File jarPath = new File(path);

        Validate.isTrue(jarPath.exists() && jarPath.isDirectory(),
                "jar包路径必须存在且为目录.");

		/* set filter */
        FileFilter jarFilter = new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getName().endsWith(".jar");
            }
        };

		/* iterate all jar */
        File[] allJars = new File(path).listFiles(jarFilter);
        List<URL> jarURLs = new ArrayList<URL>(allJars.length);

        for (int i = 0; i < allJars.length; i++) {
            try {
                jarURLs.add(allJars[i].toURI().toURL());
            } catch (Exception e) {
                throw DataXException.asDataXException(
                        FrameworkErrorCode.PLUGIN_INIT_ERROR,
                        "系统加载jar包出错", e);
            }
        }

        return jarURLs;
    }
}

缓存JarLoader

  /**
     * jarLoader的缓存
     */
    private static Map<String, JarLoader> jarLoaderCenter = new HashMap<String, JarLoader>();


    @SuppressWarnings("unchecked")
    private static synchronized Class<? extends AbstractPlugin> loadPluginClass throw Exception(
            String pluginKey, String pluginClassName) {
        JarLoader jarLoader = LoadUtil.getJarLoader(pluginKey);
        try {
            return (Class<? extends AbstractPlugin>) jarLoader
                    .loadClass(pluginClassName);
        } catch (Exception e) {
            throw e;
        }
    }

    public static synchronized JarLoader getJarLoader(String pluginKey, String pluginPath) {
        JarLoader jarLoader = jarLoaderCenter.get(pluginKey));
        if (null == jarLoader) {
            if (StringUtils.isBlank(pluginPath)) {
                throw new RunningTimeException(String.format(
                                "插件[%s]路径非法!",
                                pluginKey));
            }
            jarLoader = new JarLoader(new String[]{pluginPath});
            jarLoaderCenter.put(pluginKey, jarLoader);
        }

        return jarLoader;
    }


文章来源:https://blog.csdn.net/sinat_39488150/article/details/135816854
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云