小工具之包扫描的实现
包扫描的目的是希望以后直接用的时候,只需要提供一个包的名称,能够完成对包里面的类的扫描,遍历一遍。
package com.mec.package_scan.test.test;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public abstract class PackageScanner {
public PackageScanner() {
}
/**
* 这是一个抽象方法,处理类;
* 本工具只是完成工具使用者提供的包的扫描工作,
* 对于扫描到的类的相关具体操作不是本工具需要完成的,
* 因此给一个抽象方法,具体操作由工具使用者完成。
* @param klass
*/
public abstract void dealClass(Class<?> klass);
/**
* 根据当前目录处理包,获取包下的类并处理;
* 需要注意的是”包下还有包...“的情况,用到递归;
* @param curFile
* @param packageName
*/
public void dealPackage(File curFile, String packageName) {
File[] files = curFile.listFiles();
for (File file : files) {
if (file.isFile()) {
String fileName = file.getName();
if (!fileName.endsWith(".class")) {
continue;
}
fileName = fileName.replace(".class", "");
String className = packageName + '.' + fileName;
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else {
//这里处理包下的第二层包的情况,用到递归的思想
dealPackage(file, packageName + '.' + file.getName());
}
}
}
/**
* 处理Jar包
* @param url
*/
private void dealJar(URL url) {
try {
JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = urlConnection.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String name = jarEntry.getName();
if (jarEntry.isDirectory() || !name.endsWith(".class")) {
continue;
}
name = name.replace(".class", "");
String className = name.replace('/', '.');
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 扫描工具使用者提供的包;
* 需要注意区分Jar包和普通包的不同处理方式;
* @param packageName
*/
public void scanPackage(String packageName) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String pathName = packageName.replace('.', '/');
try {
Enumeration<URL> urls = classLoader.getResources(pathName);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
//这里需要区分是扫描jar包还是普通包
if (url.getProtocol().equals("jar")) {
dealJar(url);
} else {
try {
File curFile = new File(url.toURI());
dealPackage(curFile, packageName);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
上述的PackageScanner类中对方法和部分代码已做了注释,就不再赘述了。
那么,对于这个包扫描工具到底能够做什么,我们给一个简单的测试类来看一下运行结果。
编写一个简单的测试类:
package com.mec.package_scan.test.test;
public class Test {
public static void main(String[] args) {
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if (klass.isPrimitive()
|| klass.isAnnotation()
|| klass.isArray()
|| klass.isInterface()
|| klass.isEnum()) {
return;
}
System.out.println(klass.getName());
}
}.scanPackage("com.mec.csFramework.action");
}
}
我在这里提前导入了一个之前编写过的CSFramework框架的包,
运行结果看一下:
com.mec.csFramework.action.ActionBeanDefinition
com.mec.csFramework.action.ActionBeanFactory$1
com.mec.csFramework.action.ActionBeanFactory$2
com.mec.csFramework.action.ActionBeanFactory
com.mec.csFramework.action.ActionNotFoundException
com.mec.csFramework.action.ActionProcessor
com.mec.csFramework.action.ArgumentMaker$1
com.mec.csFramework.action.ArgumentMaker
com.mec.csFramework.action.Test
从运行结果可以看出,获取到了这个包下的所以类名称,这也就是这个工具的功能,一旦我们获取到了类名称,就可以利用反射机制进一步操作了。
当然扫描Jar包也是成功的,已测试过了,结果就不再展示了。
关于包扫描的这一小工具的实现就简单介绍到这里了。