首页 > 基础资料 博客日记
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进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
上一篇:线程的6种状态(juc编程)
下一篇:Java——本地方法(JNA)详解