zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Java中动态载入jar文件和class文件

JAVAjar文件 动态 Class 载入
2023-09-27 14:25:17 时间

概述

  诸如tomcat这种server,在启动的时候会载入应用程序中lib文件夹下的jar文件以及classes文件夹下的class文件。另外像spring这类框架,也能够依据指定的路径扫描并载入指定的类文件,这个技术能够实现一个容器,容纳各类不同的子应用。

  Java类因为须要载入和编译字节码,动态载入class文件较为麻烦。不像C载入动态链接库仅仅要一个文件名称就能够搞定,但JDK仍提供了一整套方法来动态载入jar文件和class文件。

动态载入jar文件

// 系统类库路径
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文件

// 设置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类了。