package com.lms.common.util;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @Author: 李孟帅
* @Date: 2021-12-30 15:04
* @Description:
*/
public class ClassScanner {
Map<String, Class<?>> classMap = new HashMap<>();
Predicate<String> packagePredicate;
Predicate<Class<?>> classPredicate;
public ClassScanner() {
}
public ClassScanner(Predicate<String> packagePredicate) {
this.packagePredicate = packagePredicate;
}
public ClassScanner(Predicate<String> packagePredicate, Predicate<Class<?>> classPredicate) {
this.packagePredicate = packagePredicate;
this.classPredicate = classPredicate;
}
public Map<String, Class<?>> scanAll() throws Exception {
String javaClassPath = System.getProperty("java.class.path");
String[] classPaths = javaClassPath.split(";");
for (String classPath : classPaths) {
// jar包
if (classPath.endsWith(".jar")) {
scanClassesByJar(classPath);
} else { //路径
scanClassesByPath(classPath);
}
}
return classMap;
}
// 加载路径下的class文件
private void scanClassesByPath(String classPath) {
File file = new File(classPath);
if (!file.exists()) {
return;
}
try {
if (file.isDirectory() || classPath.endsWith(".class")) {
Files.walkFileTree(Paths.get(classPath), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
try {
if (file.toString().endsWith(".class")) {
String name = file.toString().replace(classPath + File.separator, "");
// 过滤包
name = name.replace(File.separatorChar + "", ".");
if (matchPackageName(name)) {
String className = name.substring(0, name.length() - 6);
Class<?> cls = Thread.currentThread().getContextClassLoader().loadClass(className);
// 过滤类
if (matchClass(cls)) {
classMap.put(className, cls);
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return super.visitFile(file, attrs);
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 加载所有的jar包内的class文件
private void scanClassesByJar(String classPath) throws IOException {
String file = "file:/" + classPath.replace("\\", "/") + "!/";
URL url = new URL("jar", "", file);
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.getName();
// 过滤包
if (!matchPackageName(name.replace("/", "."))) {
continue;
}
// class文件
if (!jarEntry.isDirectory() && name.endsWith(".class")) {
try {
String className = name.substring(0, name.length() - 6).replace("/", ".");
Class<?> cls = Thread.currentThread().getContextClassLoader().loadClass(className);
// 过滤类
if (matchClass(cls)) {
classMap.put(className, cls);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}
// 过滤包
private boolean matchPackageName(String name) {
return packagePredicate == null || packagePredicate.test(name.replace("/", "."));
}
// 过滤类
private boolean matchClass(Class<?> cls) {
return classPredicate == null || classPredicate.test(cls);
}
public static void main(String[] args) throws Exception {
// ClassScanner classScanner = new ClassScanner(p -> p.startsWith("java.lang"));
ClassScanner classScanner = new ClassScanner(p -> p.startsWith("com.lms"), cls -> {
return Object.class.isAssignableFrom(cls);
});
Map<String, Class<?>> classMap = classScanner.scanAll();
classMap.forEach((k, v) -> System.out.println(k + " -- " + v));
}
}
使用
public static void main(String[] args) throws Exception {
// ClassScanner classScanner = new ClassScanner(p -> p.startsWith("java.lang"));
ClassScanner classScanner = new ClassScanner(p -> p.startsWith("")
, cls -> BasicLookAndFeel.class.isAssignableFrom(cls) && !Modifier.isAbstract(cls.getModifiers()));
Map<String, Class<?>> classMap = classScanner.scanAll();
classMap.forEach((k, v) -> System.out.println(k + " -- " + v));
}