包扫描
这个工具是在学了注解和反射机制后,遇到要把Model包下的所有有相关注解的类进行操作的时候遇到的。手动一个个Class.forName(className)
太麻烦了,并且还要进行相应的筛选。因此才想出来做包扫描工具,把扫描过程用一个类完成,其他如何操作向外提供。
我们知道一个工程下可能有许多的包或者Jar包,包扫描工具是为了结合注解可以准确的定位到一个需要的类上。并且扫描到一个包下的所有类方便我们使用反射机制。
包扫描工具功能:给一个包名字,扫描该包下的所有类,如何操作这些类对外提供出去。
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() {
}
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();
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();
}
}
if (file.isDirectory()) {
dealPackage(file, packageName + "." + file.getName());
}
}
}
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();
String name = jarEntry.getName();
if (jarEntry.isDirectory() || !name.endsWith(".class")) {
continue;
}
name = name.replace(".class", "");
String className = name.replace('/', '.');
Class<?> klass = Class.forName(className);
dealClass(klass);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
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();
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();
}
}
}
使用方式
public class LocalTest {
public static void main(String[] args) {
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if (klass.isPrimitive() || klass.isAnnotation() || klass.isInterface() || klass.isArray() || klass.isEnum()) {
return;
}
System.out.println(klass.getName());
}
}.scanPackage("com.mec");
}
}
需要注意的是:扫描自己的jar包可能扫描不出类很有可能是这个问题。
解决方法:
记得导出我们自己的包时,要将Add directory entries这一项勾上,否则扫描不到。
关于这里的Thread.currentThread().getContextClassLoader();
,线程的 contextClassLoader 是从父线程那里继承过来的,所谓父线程就是创建了当前线程的线程。程序启动时的 main 线程的 contextClassLoader 就是 AppClassLoader。这意味着如果没有人工去设置,那么所有的线程的 contextClassLoader 都是AppClassLoader。