Java 扫描指定包下类 (包括jar包中的java类)
在某些场景中,我们需要得到某个包名下面所有的类,不仅仅是我们自己在写的包下面java类还有一些jar包(一些第三方提供的jar包里的类,一些是自己写的类)可以看下图,其结构如此:
比如我们想得到PackageScanner.java这个类
执行这个类
打印出的URL即目前的包的位置的一串字符串,其中replace方法时为了将其变成路径的表示形式
得到file文件路径
有两种,一种是文件夹即目录,一种是文件比如.class文件
Filed.isFile() 可以判断是否为文件。Filed.isDirectory可以判断是否为目录, 但如果是目录但进入目录后还是目录,如上图文件中com->HTT->scanner则需不断判断,如此可用递归处理。
执行递归直至不是文件即是.class文件,再去处理(里面的方法时自己写的,读者可按照自己想要去怎么用去写相应的代码)
jar包处理方法与此相似,下面贴出完整代码
package com.HTT.scanner;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URI;
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 dealClassFile(String rootPackage, File curFile) {
// 以下为我自己的处理.class方式
String fileName = curFile.getName();
if (fileName.endsWith(".class")) {
fileName = fileName.replaceAll(".class", "");
try {
System.out.println("... " + rootPackage + "." + fileName);
Class<?> klass = Class.forName(rootPackage + "." + fileName);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private void dealDirectory(String rootPackage, File curFile) {
// 若为目录则继续处理目录下面的目录和.class文件
File[] fileList = curFile.listFiles();
for (File file : fileList) {
if (file.isDirectory()) {
rootPackage = rootPackage + '.' + file.getName();
System.out.println("00 " + rootPackage);
//按照文件处理
dealDirectory(rootPackage, file);
} else if (file.isFile()) {
//按照.class处理
dealClassFile(rootPackage, file);
}
}
}
private void dealJarPackage(URL url) {
try {
// 得到路径
JarURLConnection connection = (JarURLConnection) url.openConnection();
JarFile jarFile = connection.getJarFile();
// 循环执行看是否有实体的存在
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jar = jarEntries.nextElement();
// 若不是.class文件或者是目录则不处理
// 因为实体是一个个的比如这样的
com/
com/google/
com/google/gson/
com/google/gson/annotations/
com/google/gson/internal/
com/google/gson/internal/bind/
com/google/gson/internal/bind/util/
// 会将一个个列举出来
if(jar.isDirectory() || !jar.getName().endsWith(".class")) {
continue;
}
// 此处为小编我自己的处理
String jarName = jar.getName();
jarName = jarName.replace(".class", "");
jarName = jarName.replace("/", ".");
try {
System.out.println(jarName);
Class<?> klass = Class.forName(jarName);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void packageScanner(String packageName) {
String rootPacksge = packageName;
System.out.println("packageName : " + packageName);
packageName = packageName.replace(".", "/");
System.out.println("packageName : " + packageName);
URL url = Thread.currentThread().getContextClassLoader().getResource(packageName);
System.out.println("URL : " + url);
//判断协议名称是不是file,如果是file 则按照文件路径处理否则按照jar处理
if (url.getProtocol().equals("file")) {
URI uri;
try {
uri = url.toURI();
File root = new File(uri);
dealDirectory(rootPacksge, root);
} catch (URISyntaxException e) {
e.printStackTrace();
}
} else {
dealJarPackage(url);
}
}
}
package com.HTT.scanner;
import java.net.URL;
public class Test {
public static void main(String[] args) {
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
}
}.packageScanner("com.HTT.scanner");
}
}
其中dealclass是抽象方法,当要使用此类时需实现自己处理方式。
执行结果如下:
大家可能会觉得我写成这样麻烦,实则是体现了做一个工具的思想,以后这个类就可以拿到以后直接用,实例化后在抽象方法中写上自己要如何处理这个类的代码即可,而不是简简单单的写一个一次性的代码。
如果觉得有什么问题可以在下面评论哦,