反实例化
所有类实现 DeviceInterface 接口本处不做简绍
Class.forName(classPath)
Class.forName(classPath) 是 Java 反射 API 中的一个方法,用于根据给定的类名(通常是完全限定的类名,即包含包名的类名)加载类。这个方法会在类路径(classpath)中查找指定的类,并返回一个 Class 对象,该对象代表了指定类的运行时类信息。DeviceInterface.class.isAssignableFrom
判断是否对应类信息clazz.getDeclaredConstructor()
clazz.getDeclaredConstructor() 是 Java 反射 API 中的一个方法,用于获取一个类中声明的构造函数(即没有继承的构造函数)。此方法仅返回类中声明的构造函数,而不包括从父类继承的构造函数。如果类中没有任何构造函数,那么这个方法将返回 nullconstructor.newInstance();
返回实例
String classPath = devicePackAge + "." + className;
Class<?> aclazz = Class.forName(classPath);
if(DeviceInterface.class.isAssignableFrom(aclazz)){
return createInstance((Class<DeviceInterface>) aclazz);
}
private static <T> T createInstance(Class<T> clazz) throws Exception {
Constructor<T> constructor = clazz.getDeclaredConstructor();
return constructor.newInstance();
}
获取对应的包路径
在处理 Java 类加载器和资源定位时,URL 对象的 getProtocol() 方法返回的协议(protocol)指定了资源的来源类型。常见的协议有两种:file 和 jar。
- file 协议
当 URL 的协议是 file 时,它表示资源位于本地文件系统中。这种情况下,URL 的路径部分通常指向一个文件或目录的本地路径。 - jar 协议
当 URL 的协议是 jar 时,它表示资源位于一个 JAR 文件中。这种情况下,URL 的路径部分通常指向一个 JAR 文件的位置,后面跟着一个 ! 符号,再跟上一个内部路径,指示 JAR 文件内的某个资源位置。
public static List<String> getClassName(String packageName, boolean recursive) {
List<String> classes = new ArrayList<>();
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
findAndAddClassNamesByFile(packageName, filePath, recursive, classes);
} else if ("jar".equals(protocol)) {
handleJarFile(url, packageName, recursive, classes);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
获取 file 的 class 文件类名
获取项目运行时 的class 文件信息获取类名
private static void findAndAddClassNamesByFile(String packageName, String packagePath, final boolean recursive, List<String> classes) {
File dir = new File(packagePath);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
File[] dirfiles = dir.listFiles(file -> (recursive && file.isDirectory()) || (file.getName().endsWith(".class")));
if (dirfiles != null) {
for (File file : dirfiles) {
if (file.isDirectory()) {
findAndAddClassNamesByFile(
packageName + "." + file.getName(),
file.getAbsolutePath(),
recursive,
classes
);
} else {
String className = file.getName().substring(0, file.getName().length() - 6); // Remove .class extension
if (className.length() > 0) {
classes.add(className);
}
}
}
}
}
获取 jar 包class 文件类名
- 处理文件系统路径 (file 协议):
使用 URLDecoder.decode 来解码文件路径。
调用 findAndAddClassesInPackageByFile 方法来递归地查找文件系统中的类文件。 - 处理 JAR 文件 (jar 协议):
使用 URL.openStream() 打开 JAR 文件流。
创建 JarInputStream 来读取 JAR 文件中的条目。
遍历 JAR 文件中的所有条目,并检查每个条目是否是一个类文件。
如果是类文件,则将其名字添加到类列表中。
如果是目录并且递归标志为 true,则递归处理子目录。 - 递归处理子目录:
当遇到 JAR 文件中的子目录时,可以递归调用 handleJarFile 方法来处理子目录中的类文件。 getNextJarEntry
:
getNextJarEntry 是 java.util.jar.JarInputStream 类中的一个方法,用于从 JAR 文件流中读取下一个条目(即 JarEntry)。这个方法在处理 JAR 文件时非常有用,因为它允许你逐个读取 JAR 文件中的每个条目,并对其进行处理。
private static void handleJarFile(URL jarUrl, String packageName, boolean recursive, List<String> classes) throws IOException {
InputStream is = jarUrl.openStream();
JarInputStream jis = new JarInputStream(is);
try {
JarEntry entry;
while ((entry = jis.getNextJarEntry()) != null) {
String name = entry.getName();
if (name.startsWith(packageName) && name.endsWith(".class")) {
String className = name.substring(0, name.length() - 6).replace('/', '.');
classes.add(className);
} else if (recursive && entry.isDirectory()) {
String subPackageName = name.replace('/', '.').substring(0, name.length() - 1);
if (!subPackageName.equals(packageName)) {
handleJarFile(jarUrl, subPackageName, recursive, classes);
}
}
}
} finally {
jis.close();
}
}
完整Utils方法
这个是完整的 整个 utils 方法,通过filie获取跟jar 包获取, 用于获取对应的类名去反项实例化实体类去调用方法
package org.gateway.utils.scanner;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class PackageScanner {
public static List<String> getClassName(String packageName, boolean recursive) {
List<String> classes = new ArrayList<>();
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
findAndAddClassNamesByFile(packageName, filePath, recursive, classes);
} else if ("jar".equals(protocol)) {
handleJarFile(url, packageName, recursive, classes);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
private static void findAndAddClassNamesByFile(String packageName, String packagePath, final boolean recursive, List<String> classes) {
File dir = new File(packagePath);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
File[] dirfiles = dir.listFiles(file -> (recursive && file.isDirectory()) || (file.getName().endsWith(".class")));
if (dirfiles != null) {
for (File file : dirfiles) {
if (file.isDirectory()) {
findAndAddClassNamesByFile(
packageName + "." + file.getName(),
file.getAbsolutePath(),
recursive,
classes
);
} else {
String className = file.getName().substring(0, file.getName().length() - 6); // Remove .class extension
if (className.length() > 0) {
classes.add(className);
}
}
}
}
}
private static void handleJarFile(URL jarUrl, String packageName, boolean recursive, List<String> classes) throws IOException {
InputStream is = jarUrl.openStream();
JarInputStream jis = new JarInputStream(is);
try {
JarEntry entry;
while ((entry = jis.getNextJarEntry()) != null) {
String name = entry.getName();
if (name.startsWith(packageName) && name.endsWith(".class")) {
String className = name.substring(0, name.length() - 6).replace('/', '.');
classes.add(className);
} else if (recursive && entry.isDirectory()) {
String subPackageName = name.replace('/', '.').substring(0, name.length() - 1);
if (!subPackageName.equals(packageName)) {
handleJarFile(jarUrl, subPackageName, recursive, classes);
}
}
}
} finally {
jis.close();
}
}
}