包扫描的作用:
按指定包路径和要求扫描出符合条件的类,并反射出它们的类类型,在此基础上进行各种操作。
如:扫描包内含有注解的类并进行处理等。
我们的需求是对普通类进行处理的,所以在扫描时应当排除接口、枚举、注解、以及八大基本类型。
此外,在实际应用时,针对在扫描出类后所要进行的,不能在编写工具时期所能确定的操作,我们给出一个抽象方法,在扫描出每个符合条件的类后调用这个抽象方法。要求用户在实际应用时实现此方法。
public abstract void dealClass(Class<?> klass);
普通包扫描:
private void packageScan(String pathname, File currentFile) {
//File类的对象表示一个文件或文件夹
//FileFilter起到一个文件过滤器的作用,其中的accept()方法体现出了筛选过程
File[] fileList = currentFile.listFiles(new FileFilter() {
//只筛选出“.class”和文件夹的File对象
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory()) {
return true;
}
return pathname.getName().endsWith(".class");
}
});
for(File file : fileList) {
String fileName = file.getName();
if(file.isDirectory()) {
//构建出当前文件夹所表示的包路径,递归扫描
packageScan(pathname + "." + file.getName(), file);
} else {
//构建出类名称并进行反射,进一步筛选
String className = pathname + "." + fileName.replace(".class", "");
try {
Class<?> klass = Class.forName(className);
if(klass.isAnnotation()
|| klass.isInterface()
|| klass.isEnum()
|| klass.isPrimitive()) {
continue;
}
dealClass(klass);//未来的处理
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
Jar包扫描:
至于jar包扫描,需要用到一些前人所提供的工具,初学者看到也不必惊慌,拿来用就是了。
private void scanPackage(URL url) throws IOException {
JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = urlConnection.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String jarName = jarEntry.getName();
if (jarEntry.isDirectory() || !jarName.endsWith(".class")) {
continue;
}
String className = jarName.replace(".class", "").replaceAll("/", ".");
try {
Class<?> klass = Class.forName(className);
if (klass.isAnnotation()
|| klass.isInterface()
|| klass.isEnum()
|| klass.isPrimitive()) {
continue;
}
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
综合:
public void packageScan(String pathname) {
String opperPathname = pathname.replace('.', '/');
//得到当前上下文的类加载器(动态加载类到JVM中)
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Enumeration<URL> resources = classLoader.getResources(opperPathname);
while(resources.hasMoreElements()) {
URL url = resources.nextElement();
if(url.getProtocol().equals("jar")) {
//扫描jar包
scanPackage(url);
} else {
//普通包扫描
File file = new File(url.toURI());
if (!file.exists()) {
continue;
}
packageScan(pathname, file);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
这样包扫描的基本功能就完成了。在此基础上我们在给上几种方法的重载,让我们的工具能适应的情况多一些。
public void packageScan(Class<?> klass) {
packageScan(klass.getPackage().getName());
}
public void packageScan(Class<?>[] classes) {
for(Class<?> klass : classes) {
packageScan(klass);
}
}
public void packageScan(String[] packages) {
for(String packageName : packages) {
packageScan(packageName);
}
}