有时我们需要在整个项目内扫描一些类型的类,有可能是实现了某个类型的子类,或者是加了某注解的类,这时候我们可以借助Spring的Bean扫描来完成这些功能。

本博客参考 博客 springboot自定义注解,项目启动时扫描注解类并注入容器
, 感谢大佬!

思路

spring为了能支持扫描,提供了 ClassPathScanningCandidateComponentProvider ,可以借助他来扫描。下面是代码:

@AllArgsConstructor
public class DataPermissionRegister {
    /**
     * 资源加载器
     */
    private final ResourceLoader resourceLoader;
    /**
     * 环境
     */
    private final Environment environment;

    @PostConstruct
    public void init() {
        if (log.isInfoEnabled()){
            log.info("start DataPermissionRegister ");
        }

        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(resourceLoader);

        // 设置扫描器scanner扫描的过滤条件 还支持扫描指定类型(包括继承他的类)  AssignableTypeFilter
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(DataPermission.class);
        scanner.addIncludeFilter(annotationTypeFilter);

        // 获取指定要扫描的basePackages
        Set<String> basePackages = Set.of("com.bbb", "com.aaa");

        // 遍历每一个basePackages
        for (String basePackage : basePackages) {
            // 通过scanner获取basePackage下的候选类(有标@SimpleRpcClient注解的类)
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            // 遍历每一个候选类,如果符合条件就把他们注册到容器
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition beanDefinition) {
                    // candidateComponent 有很多class的信息,下面举例是获取class上的指定注解
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
        Map<String, Object> dataPermissionAttrs = annotationMetadata.getAnnotationAttributes(DataPermission.class.getCanonicalName());
        // ...剩余处理,注册 或者其他
                }
            }
        }

        if (log.isInfoEnabled()){
            log.info("dataPermissionRegister init success!");
        }
    }

    

    /**
     * 创建扫描器
     */
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                // 注解类型的class就不要了
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }
}

注意,这里扫描做出来class并没有把他注册到spring容器中,如果有这个需要,请参考上面提到的播客。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐