ClassScanner 类扫描器
# 1. 功能概述
ClassScanner 是 Hutool 提供的类扫描器工具,用于扫描指定包路径下的所有类文件,并根据过滤器条件返回符合条件的类集合。该工具支持扫描文件系统和 jar 包中的类,提供了丰富的扫描方式和过滤条件,简化了 Java 应用中类的自动发现和加载过程。
# 2. 核心功能
# 2.1 按注解扫描
- scanAllPackageByAnnotation(packageName, annotationClass):扫描指定包路径下所有包含指定注解的类(包括其他加载的 jar)
- scanPackageByAnnotation(packageName, annotationClass):扫描指定包路径下所有包含指定注解的类(仅扫描 classpath)
# 2.2 按父类/接口扫描
- scanAllPackageBySuper(packageName, superClass):扫描指定包路径下所有指定类或接口的子类或实现类(包括其他加载的 jar)
- scanPackageBySuper(packageName, superClass):扫描指定包路径下所有指定类或接口的子类或实现类(仅扫描 classpath)
# 2.3 全量扫描
- scanAllPackage():扫描所有 class 文件(包括其他加载的 jar)
- scanPackage():扫描 classpath 下所有 class 文件
# 2.4 自定义过滤扫描
- scanAllPackage(packageName, classFilter):扫描指定包路径下满足过滤器条件的所有 class 文件(包括其他加载的 jar)
- scanPackage(packageName, classFilter):扫描指定包路径下满足过滤器条件的所有 class 文件(仅扫描 classpath)
# 2.5 配置与结果获取
- setIgnoreLoadError(ignoreLoadError):设置是否忽略加载错误
- setInitialize(initialize):设置是否在扫描到类时初始化类
- setClassLoader(classLoader):设置自定义的类加载器
- getClassesOfLoadError():获取加载错误的类名字集合
# 3. 方法详解
# 3.1 按注解扫描
# scanAllPackageByAnnotation(packageName, annotationClass)
功能:扫描指定包路径下所有包含指定注解的类
参数:
packageName:包路径,null表示扫描全部annotationClass:注解类
返回值:类集合
说明:包括其他加载的 jar 或者类
示例:
// 扫描所有包含 @Service 注解的类
Set<Class<?>> serviceClasses = ClassScanner.scanAllPackageByAnnotation(null, Service.class);
# scanPackageByAnnotation(packageName, annotationClass)
功能:扫描指定包路径下所有包含指定注解的类
参数:
packageName:包路径,null表示扫描全部annotationClass:注解类
返回值:类集合
说明:如果 classpath 下已经有类,不再扫描其他加载的 jar 或者类
示例:
// 扫描 com.example 包下所有包含 @Controller 注解的类
Set<Class<?>> controllerClasses = ClassScanner.scanPackageByAnnotation("com.example", Controller.class);
# 3.2 按父类/接口扫描
# scanAllPackageBySuper(packageName, superClass)
功能:扫描指定包路径下所有指定类或接口的子类或实现类
参数:
packageName:包路径,null表示扫描全部superClass:父类或接口(不包括)
返回值:类集合
说明:不包括指定父类本身,包括其他加载的 jar 或者类
示例:
// 扫描所有 List 接口的实现类
Set<Class<?>> listImplClasses = ClassScanner.scanAllPackageBySuper(null, List.class);
# scanPackageBySuper(packageName, superClass)
功能:扫描指定包路径下所有指定类或接口的子类或实现类
参数:
packageName:包路径,null表示扫描全部superClass:父类或接口(不包括)
返回值:类集合
说明:不包括指定父类本身,仅扫描 classpath
示例:
// 扫描 com.example 包下所有 Animal 类的子类
Set<Class<?>> animalSubClasses = ClassScanner.scanPackageBySuper("com.example", Animal.class);
# 3.3 全量扫描
# scanAllPackage()
功能:扫描该包路径下所有 class 文件
返回值:类集合
说明:包括其他加载的 jar 或者类
示例:
// 扫描所有类
Set<Class<?>> allClasses = ClassScanner.scanAllPackage();
# scanPackage()
功能:扫描 classpath 下所有 class 文件
返回值:类集合
说明:如果 classpath 下已经有类,不再扫描其他加载的 jar 或者类
示例:
// 扫描 classpath 下所有类
Set<Class<?>> classpathClasses = ClassScanner.scanPackage();
# 3.4 自定义过滤扫描
# scanAllPackage(packageName, classFilter)
功能:扫描包路径下和所有在 classpath 中加载的类,满足 class 过滤器条件的所有 class 文件
参数:
packageName:包路径,如 com、com.、com.abs、com.abs.classFilter:class 过滤器,过滤掉不需要的 class
返回值:类集合
说明:包括其他加载的 jar 或者类
示例:
// 扫描所有以 Service 结尾的类
Set<Class<?>> serviceClasses = ClassScanner.scanAllPackage(null, clazz -> clazz.getName().endsWith("Service"));
# scanPackage(packageName, classFilter)
功能:扫描包路径下满足 class 过滤器条件的所有 class 文件
参数:
packageName:包路径,如 com、com.、com.abs、com.abs.classFilter:class 过滤器,过滤掉不需要的 class
返回值:类集合
说明:仅扫描 classpath
示例:
// 扫描 com.example 包下所有公共类
Set<Class<?>> publicClasses = ClassScanner.scanPackage("com.example", clazz -> Modifier.isPublic(clazz.getModifiers()));
# 3.5 配置与结果获取
# setIgnoreLoadError(ignoreLoadError)
功能:设置是否忽略加载错误
参数:
ignoreLoadError:是否忽略错误
示例:
ClassScanner scanner = new ClassScanner();
scanner.setIgnoreLoadError(true);
# setInitialize(initialize)
功能:设置是否在扫描到类时初始化类
参数:
initialize:是否初始化类
示例:
ClassScanner scanner = new ClassScanner();
scanner.setInitialize(true);
# setClassLoader(classLoader)
功能:设置自定义的类加载器
参数:
classLoader:类加载器
示例:
ClassScanner scanner = new ClassScanner();
scanner.setClassLoader(Thread.currentThread().getContextClassLoader());
# getClassesOfLoadError()
功能:获取加载错误的类名字集合
返回值:加载错误的类名字集合
示例:
ClassScanner scanner = new ClassScanner();
scanner.setIgnoreLoadError(true);
Set<Class<?>> classes = scanner.scan();
Set<String> errorClasses = scanner.getClassesOfLoadError();
# 4. 示例代码
# 4.1 基本用法
// 扫描指定包下的所有类
Set<Class<?>> classes = ClassScanner.scanPackage("com.example");
Console.log("扫描到 {} 个类", classes.size());
for (Class<?> clazz : classes) {
Console.log("类名:{}", clazz.getName());
}
# 4.2 按注解扫描
// 定义一个自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation {
}
// 使用注解
@MyAnnotation
class MyClass {
}
// 扫描包含自定义注解的类
Set<Class<?>> annotatedClasses = ClassScanner.scanPackageByAnnotation(null, MyAnnotation.class);
Console.log("包含 @MyAnnotation 注解的类:{}", annotatedClasses);
# 4.3 按父类扫描
// 定义父类
abstract class Parent {
}
// 定义子类
class Child1 extends Parent {
}
class Child2 extends Parent {
}
// 扫描所有 Parent 的子类
Set<Class<?>> subClasses = ClassScanner.scanPackageBySuper(null, Parent.class);
Console.log("Parent 的子类:{}", subClasses);
# 4.4 自定义过滤器
// 扫描所有实现了 Runnable 接口且名字包含 Thread 的类
Set<Class<?>> runnableClasses = ClassScanner.scanAllPackage(null, clazz -> {
return Runnable.class.isAssignableFrom(clazz) && clazz.getName().contains("Thread");
});
Console.log("符合条件的 Runnable 实现类:{}", runnableClasses);
# 4.5 高级配置
// 创建扫描器实例
ClassScanner scanner = new ClassScanner("com.example");
// 配置扫描器
scanner.setIgnoreLoadError(true); // 忽略加载错误
scanner.setInitialize(false); // 不初始化类
scanner.setClassLoader(ClassLoader.getSystemClassLoader()); // 设置类加载器
// 执行扫描
Set<Class<?>> classes = scanner.scan(true); // 强制扫描所有类路径
// 获取结果
Console.log("扫描到 {} 个类", classes.size());
// 获取加载错误的类
Set<String> errorClasses = scanner.getClassesOfLoadError();
if (!errorClasses.isEmpty()) {
Console.log("加载错误的类:{}", errorClasses);
}
# 5. 注意事项
- 包路径格式:包路径可以是多种格式,如 com、com.、com.abs、com.abs.
- 类名歧义处理:工具类会处理类名歧义,例如 cn.hutool.v7.A 和 cn.hutool.v7.ATest
- 异常处理:对于无法加载的类,工具类会自动忽略,不会抛出异常
- jar 包支持:支持扫描 jar 包中的类
- 线程安全:ClassScanner 类是可序列化的,但扫描过程不是线程安全的
- 类加载器:默认使用当前线程的类加载器
- 初始化控制:可以控制是否初始化扫描到的类
- 结果不可修改:返回的类集合是不可修改的
# 6. 最佳实践
- 按需扫描:只扫描需要的包路径,避免全量扫描影响性能
- 合理使用过滤器:使用过滤器减少返回的类数量,提高处理效率
- 结合注解使用:利用注解扫描可以方便地发现特定功能的类
- 父类/接口扫描:当需要查找所有实现了某接口的类时,使用父类/接口扫描
- 错误处理:设置
ignoreLoadError(true)可以忽略因依赖问题导致的类加载失败 - 避免重复扫描:对于频繁使用的扫描结果,建议缓存
- 初始化控制:根据需要控制是否初始化类,避免不必要的资源消耗
- 自定义类加载器:在复杂的类加载环境中,使用自定义类加载器确保正确加载类
ClassScanner 工具类为 Java 应用提供了强大的类扫描能力,简化了类的自动发现和加载过程。它支持多种扫描方式和灵活的配置选项,可以满足不同场景下的类扫描需求。无论是基于注解、父类/接口还是自定义条件,ClassScanner 都能高效地扫描并返回符合条件的类集合。