有时我们需要在整个项目内扫描一些类型的类,有可能是实现了某个类型的子类,或者是加了某注解的类,这时候我们可以借助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.yonyou", "com.changan");
// 遍历每一个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容器中,如果有这个需要,请参考上面提到的播客。