1. 声明
当前内容主要为本人学习和复习从jar文件中读取class的操作
主要包括:
- 使用JarFile方式读取
- 使用JarInputStream方式读取
主要参考官方api文档
2. JarFile方式
Jar就是Zip文件的一种
首先准备一个需要读取的jar(myCommons.jar)
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
*
* @author hy
* @createTime 2021-06-20 09:41:55
* @description 读取jar的内容并获得解析(使用jarFile方式)
*
*/
public class ReadJarTestUsingJarFile {
public static void main(String[] args) throws MalformedURLException {
String jarFilePath = "C:\\Users\\admin\\Desktop\\java的测试\\commons-test\\myCommons.jar";
File file = new File(jarFilePath);
if (!file.exists()) {
System.out.println("文件不存在!");
return;
}
if (!file.isFile()) {
System.out.println("读取的为文件夹而非文件!");
return;
}
if (!file.canRead()) {
System.out.println("当前文件不可读!");
return;
}
URL url1 = file.toURI().toURL();
URLClassLoader jarUrlClassLoader = new URLClassLoader(new URL[] { url1 },
Thread.currentThread().getContextClassLoader());
JarFile jarFile = null;
try {
jarFile = new JarFile(file);
// 获取jar中实际的MAINFEST.MF文件
Manifest manifest = jarFile.getManifest();
pringManifestFile(manifest);
// 开始获取jar中的.class文件
Enumeration<JarEntry> entries = jarFile.entries();
List<String> classNames = getClassNames(entries);
classNames.forEach(x -> {
if (x.endsWith("MySQLConnectionCliTest")) {
loadAndInstanceClass(x, jarUrlClassLoader);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
*
* @author hy
* @createTime 2021-06-20 10:31:25
* @description 加载类和实例化类
* @param clazzName
* @param classLoader
*
*/
private static void loadAndInstanceClass(String clazzName, ClassLoader classLoader) {
try {
// 需要使用其他的classLoader加载
Class<?> forName = classLoader.loadClass(clazzName);
System.out.println(forName);
try {
Object newInstance = forName.newInstance();
System.out.println(newInstance);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*
* @author hy
* @createTime 2021-06-20 10:24:46
* @description 打印并获取所有的class
* @param entries
* @param classloader
*
*/
private static List<String> getClassNames(Enumeration<JarEntry> entries) {
List<String> classNames = new ArrayList<String>();
while (entries.hasMoreElements()) {
JarEntry nextElement = entries.nextElement();
String name = nextElement.getName();
// 这个获取的就是一个实体类class java.util.jar.JarFile$JarFileEntry
// Class<? extends JarEntry> class1 = nextElement.getClass();
System.out.println("entry name=" + name);
// 这样就获取所有的jar中的class文件
// 加载某个class文件,并实现动态运行某个class
if (name.endsWith(".class")) {
String replace = name.replace(".class", "").replace("/", ".");
classNames.add(replace);
}
}
return classNames;
}
/**
*
* @author hy
* @createTime 2021-06-20 10:32:16
* @description 输出当前的manifest文件中的信息内容
* @param manifest
*
*/
private static void pringManifestFile(Manifest manifest) {
Attributes mainAttributes = manifest.getMainAttributes();
Set<Entry<Object, Object>> entrySet = mainAttributes.entrySet();
Iterator<Entry<Object, Object>> iterator = entrySet.iterator();
// 打印并显示当前的MAINFEST.MF文件中的信息
while (iterator.hasNext()) {
Entry<Object, Object> next = iterator.next();
Object key = next.getKey();
Object value = next.getValue();
// 这里可以获取到Class-Path,或者某个执行的Main-Class
System.out.println(key + ": " + value);
}
}
}
处理方式和处理zip文件是一样的,执行的结果为:
读取到MANIFEST.MF文件和class文件
,而且实例创建成功,注意需要URLClassLoader
3. JarInputStream方式
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
/**
*
* @author hy
* @createTime 2021-06-20 09:41:55
* @description 读取jar的内容并获得解析(使用jarInputStream方式)
*
*/
public class ReadJarTestUsingJarInputStream {
public static void main(String[] args) throws MalformedURLException {
String jarFilePath = "C:\\Users\\admin\\Desktop\\java的测试\\commons-test\\myCommons.jar";
File file = new File(jarFilePath);
if (!file.exists()) {
System.out.println("文件不存在!");
return;
}
if (!file.isFile()) {
System.out.println("读取的为文件夹而非文件!");
return;
}
if (!file.canRead()) {
System.out.println("当前文件不可读!");
return;
}
URL url1 = file.toURI().toURL();
// 必须使用urlClassLoader,才能实例化当前加载的类
URLClassLoader jarUrlClassLoader = new URLClassLoader(new URL[] { url1 },
Thread.currentThread().getContextClassLoader());
try (JarInputStream jis = new JarInputStream(new FileInputStream(file))) {
Manifest manifest = jis.getManifest();
pringManifestFile(manifest);
JarEntry nextJarEntry = jis.getNextJarEntry();
while (nextJarEntry != null) {
String className = getClassName(nextJarEntry);
if (className != null && className.endsWith("MySQLConnectionCliTest")) {
loadAndInstanceClass(className, jarUrlClassLoader);
}
nextJarEntry = jis.getNextJarEntry();
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
/**
*
* @author hy
* @createTime 2021-06-20 10:31:25
* @description 加载类和实例化类
* @param clazzName
* @param classLoader
*
*/
private static void loadAndInstanceClass(String clazzName, ClassLoader classLoader) {
try {
// 需要使用其他的classLoader加载
Class<?> forName = classLoader.loadClass(clazzName);
System.out.println(forName);
try {
Object newInstance = forName.newInstance();
System.out.println(newInstance);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static String getClassName(JarEntry entry) {
String name = entry.getName();
// 这个获取的就是一个实体类class java.util.jar.JarFile$JarFileEntry
// Class<? extends JarEntry> class1 = nextElement.getClass();
System.out.println("entry name=" + name);
// 加载某个class文件,并实现动态运行某个class
if (name.endsWith(".class")) {
String replace = name.replace(".class", "").replace("/", ".");
return replace;
}
return null;
}
/**
*
* @author hy
* @createTime 2021-06-20 10:32:16
* @description 输出当前的manifest文件中的信息内容
* @param manifest
*
*/
private static void pringManifestFile(Manifest manifest) {
Attributes mainAttributes = manifest.getMainAttributes();
Set<Entry<Object, Object>> entrySet = mainAttributes.entrySet();
Iterator<Entry<Object, Object>> iterator = entrySet.iterator();
// 打印并显示当前的MAINFEST.MF文件中的信息
while (iterator.hasNext()) {
Entry<Object, Object> next = iterator.next();
Object key = next.getKey();
Object value = next.getValue();
// 这里可以获取到Class-Path,或者某个执行的Main-Class
System.out.println(key + ": " + value);
}
}
}
执行结果为:
注意这里的JarInputStream是通过判断 jis.getNextJarEntry();并判断是否为null方式判断是否还有下一个元素
执行成功!