我要写一个包扫描工具,该工具实现从指定目录往下遍历,最终找到以.class文件结尾的类,将该类的元类对象以抽象方法参数的形式传给用户。
步骤: 1. 根据指定目录找出绝对路径,根据Protocol(协议)将目录分为jar目录和普通目录;
2. 分别处理jar目录和普通目录。
3. 处理至找到了以.class文件结尾的类,将这个类的元类对象以抽象方法参数的形式传给用户。
直接贴代码:
package com.mec.util;
import java.io.File;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public abstract class PackageScanner {
public PackageScanner() {
}
public void scannerPackage(String packageName) {
String packagePath = packageName.replace('.', '/');
//Eclipse下父目录与子目录以.相隔
//真正的路径中是以‘/’或‘\’相隔,此路径以‘\’相隔
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Enumeration<URL> resources = classLoader.getResources(packagePath);
//得到绝对路径
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
if (url.getProtocol().equals("jar")) {
//通过Protocol(协议)可以区分开jar文件和普通文件
scannerJar(url);
// 将处理jar文件的代码单独写成一个内部方法,避免代码量过大
} else {
File root = new File(url.toURI());
//将url转化成uri,以此创建File对象,后面解析就变成了对File的处理
scannerDirectory(root, packageName);
// 同理将处理普通文件的代码单独也写成一个内部方法
}
}
} catch ( Exception e) {
e.printStackTrace();
}
}
private void scannerDirectory(File currentFile, String packageName) {
if (!currentFile.isDirectory()) {
return;
}
File[] files = currentFile.listFiles();
// 得到File对象类型的【完整路径】的数组
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".class")) {
String fileName = file.getName().replace(".class", "");
//去除掉后缀 .class
String className = packageName + "." + fileName;
// 得到带包名的类,为取得元类对象做准备
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
//将得到的元类对象通过抽象方法参数传递给用户,以便用户后续操作。
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else if (file.isDirectory()) {
scannerDirectory(file, packageName + "." + file.getName());
// 此处采用递归,只要是目录就继续往下一层遍历,直到file.isFile()为true,且以.class结尾
}
}
}
private void scannerJar(URL url) {
try {
JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = urlConnection.getJarFile();
// 取得jar文件的引用
Enumeration<JarEntry> jarEntries = jarFile.entries();
//JarFile 的 entries 方法返回一个所有条目的 Enumeration 对象
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
//开始遍历,每个个体都是一个 JarEntry, 存在getName()方法
String name = jarEntry.getName();
if (jarEntry.isDirectory() || !name.endsWith(".class")) {
continue;
}
name = name.replace(".class", ""); //去除掉后缀 .class
String className = name.replace('/', '.');
Class<?> klass = Class.forName(className);
dealClass(klass);
//将得到的元类对象通过抽象方法参数传递给用户,以便用户后续操作。
}
} catch (Exception e) {
e.printStackTrace();
}
}
public abstract void dealClass(Class<?> klass);
}
经测试,上述代码可以完成包扫描过程。如果有些地方看不懂,可以上网查一查 。初学者学到这时,不应被 " 巫师的咒语 "吓倒,因为工具复杂,而不愿接受。相反,应站在工具本身发挥的作用角度来思考。积累的多了,见识的广了,才有资格去参悟那些 “ 巫师的咒语 ”。