这篇文章主要介绍一个包扫描工具。
包扫描工具的功能:通过给定一个包名称,该工具会根据给定的包名称自动扫描并得到该包下的所有文件,并通过抽象方法将该文件进行处理。这里的包主要分为普通包和Jar包,通过Protocol(协议)来判断是普通包还是Jar包,然后分别处理,将处理后得到的类作为抽象方法的参数交由外部处理该类。
下面我们来看一下具体实现过程:
public abstract class PackageScanner {
//无参构造方法
public PackageScanner() {
}
//抽象方法,将包扫描得到的类交给外部处理(用户处理)
public abstract void dealClass(Class<?> klass);
//处理普通包
private void dealPackage(File curFile, String packageName) {
//得到当前文件夹下的所有文件或子文件夹
File[] files = curFile.listFiles();
//对所得到的文件或子文件夹进行遍历
for (File file : files) {
//判断是否为文件,如果是文件,则进一步处理;反之如果是文件夹则继续扫描直到是文件
if (file.isFile()) {
String fileName = file.getName();
/判断该文件是否是.class文件,若不是不做处理
if (!fileName.endsWith(".class")) {
continue;
}
//例如:Gson.class --> Gson
fileName = fileName.replace(".class", "");
//得到类名(如:com.google.gson.Gson)
String className = packageName + "." + fileName;
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else {
//这里运用了递归,如果是文件夹就一直扫描,直到扫描到文件
dealPackage(file, packageName + "." + file.getName());
}
}
}
//处理Jar包
private void dealJar(URL url) {
try {
JarURLConnection connection = (JarURLConnection) url.openConnection();
JarFile jarFile = connection.getJarFile();
Enumeration<JarEntry> entryList = jarFile.entries();
while (entryList.hasMoreElements()) {
JarEntry jarEntry = entryList.nextElement();
//如果该文件是目录或者不是以.class结尾,则不做处理
if (jarEntry.isDirectory() || !jarEntry.getName().endsWith(".class")) {
continue;
}
String className = jarEntry.getName();
//将文件路径名转换成包名称的形式
className = className.replace(".class", "");
className = className.replace("/", ".");
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//给定包名称,开始包扫描
public void scanPackage(String packageName) {
//得到当前线程的类加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//将包名称转换成路径名称
String pathName = packageName.replace(".", "/");
try {
//由类加载器得到URL的枚举
Enumeration<URL> urls = classLoader.getResources(pathName);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
//得到URL的协议并判断是否为Jar包
if (url.getProtocol().equals("jar")) {
dealJar(url);//如果是,处理Jar包
} else {
//反之处理普通包
try {
//根据URL得到当前目录(文件夹)
File curFile = new File(url.toURI());
dealPackage(curFile, packageName);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
下面我们来测试一下,扫描一下Jar包,这里我只截取了一部分:
测试代码如下
public class Test {
public static void main(String[] args) {
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if (klass.isPrimitive()
|| klass.isAnnotation()
|| klass.isInterface()
|| klass.isEnum()
|| klass.isArray()) {
return;
}
System.out.println(klass.getName());
}
}.scanPackage("com.google.gson");//这里扫描的是Jar包
}
}
测试结果(只贴出来了一部分):
com.google.gson.DefaultDateTypeAdapter
com.google.gson.FieldAttributes
com.google.gson.FieldNamingPolicy$1
com.google.gson.FieldNamingPolicy$2
com.google.gson.FieldNamingPolicy$3
com.google.gson.FieldNamingPolicy$4
com.google.gson.FieldNamingPolicy$5
com.google.gson.Gson$1
com.google.gson.Gson$2
com.google.gson.Gson$3
com.google.gson.Gson$4
com.google.gson.Gson$5
com.google.gson.Gson$6
com.google.gson.Gson$FutureTypeAdapter
由此可以看出,这个包扫描工具是成功的,以后可以打成jar包使用。