Java实现从指定路径加载jar包/class文件
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java实现从指定路径加载jar包/class文件,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5931字,纯文字阅读大概需要9分钟。
内容图文
![Java实现从指定路径加载jar包/class文件](/upload/InfoBanner/zyjiaocheng/753/9b1f736f74aa4be195ed67d65132524c.jpg)
项目背景:
在线计算开发平台在 yarn客户端 提交机上 提交Flink任务时,需要加载 非结构化数据解析器jar 和 自定义函数jar
方案:
考虑到 java 自带的 ClassLoader 无法灵活的添加某路径下的类,考虑以下三种方式实现:
- AppClassLoader 继承自 URLClassLoader,以反射的方式将 addURL 方法设置为 public,以添加自定义路径为 classpath
- 自定义类加载器实现 URLClassLoader,将 addURL 由 protected 变更为 public,以方便添加自定义路径为 classpath
- 自定义类加载器实现 ClassLoader,将本地类文件读入byte[],调用 defineClass 方法生成类
demo说明:
-
方案一和方案二本质上是一样的,此处只实现方案一
demo类:ExtClasspathLoader.java
-
方案三扩展性更强,不仅仅可以实现加载类,也可实现加载资源文件。但是使用各个类时,必须手动引入,而方案一和方案二可以把路径上的所有类都自动引入
demo类:DiskClassLoader.java
参考:https://blog.csdn.net/briblue/article/details/54973413
ExtClasspathLoader.java
package com.wj.classloader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
/**
* 根据properties中配置的路径把jar和配置文件加载到classpath中。<br>
* 此工具类加载类时使用的是SystemClassLoader,如有需要对加载类进行校验,请另外实现自己的加载器 *
*/
public class ExtClasspathLoader {
private static final Logger LOG = LoggerFactory.getLogger(ExtClasspathLoader.class);
private static final String JAR_SUFFIX = ".jar";
private static final String ZIP_SUFFIX = ".zip";
/**
* URLClassLoader的addURL方法
*/
private static Method addURL = initAddMethod();
/**
* Application Classloader
*/
private static URLClassLoader classloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
/**
* 初始化addUrl 方法.
*
* @return 可访问addUrl方法的Method对象
*/
private static Method initAddMethod() {
try {
Method add = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
add.setAccessible(true);
return add;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 通过filepath加载文件到classpath。
*
* @param file 文件路径
*/
private static void addURL(File file) throws Exception {
addURL.invoke(classloader, file.toURI().toURL());
}
/**
* load Resource by Dir
*
* @param file dir
*/
public static void loadResource(File file) throws Exception {
// 资源文件只加载路径
LOG.info("load Resource of dir : " + file.getAbsolutePath());
if (file.isDirectory()) {
addURL(file);
File[] subFiles = file.listFiles();
if (subFiles != null) {
for (File tmp : subFiles) {
loadResource(tmp);
}
}
}
}
/**
* load Classpath by Dir
*
* @param file Dir
*/
public static void loadClasspath(File file) throws Exception {
LOG.info("load Classpath of dir : " + file.getAbsolutePath());
if (file.isDirectory()) {
File[] subFiles = file.listFiles();
if (subFiles != null) {
for (File subFile : subFiles) {
loadClasspath(subFile);
}
}
} else {
if (file.getAbsolutePath().endsWith(JAR_SUFFIX) || file.getAbsolutePath().endsWith(ZIP_SUFFIX)) {
addURL(file);
}
}
}
}
方法 loadClasspath 和 loadResource 分别可以加载 指定路径 下的jar 和 资源文件,此方案使用最为方便。
具体使用方法,可查看最后的测试demo。
ExtClasspathLoader.java
package com.wj.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
/**
* 从本地加载文件
*/
public class DiskClassLoader extends ClassLoader {
private String mLibPath;
public DiskClassLoader(String path) {
mLibPath = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String fileName = getFileName(name);
File file = new File(mLibPath, fileName);
try {
FileInputStream is = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
try {
while ((len = is.read()) != -1) {
bos.write(len);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] data = bos.toByteArray();
is.close();
bos.close();
return defineClass(name, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
/**
* 获取要加载 的class文件名
*
* @param name String
* @return String
*/
private String getFileName(String name) {
int index = name.lastIndexOf('.');
if (index == -1) {
return name + ".class";
} else {
return name.substring(index + 1) + ".class";
}
}
@Override
public URL getResource(String name) {
return super.getResource(name);
}
}
此方式适合加载指定路径上的某个文件,具体使用方法,可查看最后的测试demo。
使用示例
package com.wj.classloader;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试 ExtClasspathLoader 和 DiskClassLoader
*/
public class Main {
private static final String PATH = "E:\\IDEJ_workspace\\wj_proj\\java-se\\src\\main\\java\\com\\wj\\classloader\\Person.java";
private static final String CLASS_FULL_NAME = "com.wj.classloader.Person";
public static void main(String[] args) throws Exception {
System.out.println("测试 DiskClassLoader.");
testDiskClassLoader();
System.out.println("---------------------");
System.out.println("测试 ExtClasspathLoader.");
testExtClasspathLoader();
}
private static void testExtClasspathLoader() throws Exception {
ExtClasspathLoader.loadClasspath(new File(PATH));
Object obj = Class.forName(CLASS_FULL_NAME).newInstance();
System.out.println(obj);
}
private static void testDiskClassLoader() {
// 创建自定义classloader对象
DiskClassLoader diskLoader = new DiskClassLoader(PATH);
try {
// 加载class文件
Class c = diskLoader.loadClass(CLASS_FULL_NAME);
if (c != null) {
try {
Object obj = c.newInstance();
Method method = c.getDeclaredMethod("say", null);
//通过反射调用Test类的say方法
method.invoke(obj, null);
System.out.println(obj);
} catch (InstantiationException | IllegalAccessException
| NoSuchMethodException
| SecurityException |
IllegalArgumentException |
InvocationTargetException e) {
e.printStackTrace();
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Person.java
package com.wj.classloader;
/**
* 测试类 Person
*/
public class Person {
public void say() {
System.out.println("I am wj.");
}
}
测试结果如下:
结论:DiskClassLoader 和 ExtClasspathLoader 方式都能实现加载Person类,且都能正常使用
内容总结
以上是互联网集市为您收集整理的Java实现从指定路径加载jar包/class文件全部内容,希望文章能够帮你解决Java实现从指定路径加载jar包/class文件所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。