自定义注解扫描
场景
在 spring 环境下,很多情况下可能会自定义注解,自定义注解需要自动注入到 spring IOC容器中,所以就需要扫描这些自定义注解
AnnoScan 注解扫描器
/**
* 自定义扫描注解,将扫描的bean加入到spring IOC容器中
* @Date: 2024/4/18 16:26
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Import(MyScannerRegistrar.class)
@Documented
public @interface AnnoScan {
/**
* 扫描指定包
* @return
*/
String[] basePackage() default {};
/**
* 指定扫描注解
* @return
*/
Class<? extends Annotation>[] annotations();
}
注解扫描处理器
@Slf4j
public class MyScannerRegistrar implements ImportBeanDefinitionRegistrar {
private static final String BASE_PACKAGE = "basePackage";
private static final String ANNOTATIONS = "annotations";
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(AnnoScan.class.getName()));
if (annotationAttributes == null) {
throw new RuntimeException("未注定必须属性");
}
Class<? extends Annotation>[] annos = getScanAnnotations(annotationMetadata, annotationAttributes);
String[] basePackage = getBasePackage(annotationMetadata, annotationAttributes);
log.info("MyScanner scan packages: {}", basePackage);
for (Class<? extends Annotation> anno : annos) {
MyScanner myScanner = new MyScanner(registry, anno);
int count = myScanner.scan(basePackage);
log.info("MyScanner scan annotation 【@{}】 count: 【{}】", anno.getSimpleName(), count);
}
}
private Class<? extends Annotation>[] getScanAnnotations(AnnotationMetadata annotationMetadata, AnnotationAttributes annotationAttributes) {
Class<?>[] annos = annotationAttributes.getClassArray(ANNOTATIONS);
if (annos == null || annos.length == 0) {
throw new RuntimeException("未指定扫描注解类型");
}
return (Class<? extends Annotation>[]) annos;
}
private String[] getBasePackage(AnnotationMetadata annotationMetadata, AnnotationAttributes annotationAttributes) {
String[] basePackages = annotationAttributes.getStringArray(BASE_PACKAGE);
if (basePackages == null || basePackages.length == 0) {
basePackages = new String[]{((StandardAnnotationMetadata) annotationMetadata).getIntrospectedClass().getPackage().getName()};
}
return basePackages;
}
}
MyScanner
@Slf4j
public class MyScanner extends ClassPathBeanDefinitionScanner {
public MyScanner(BeanDefinitionRegistry registry, Class<? extends Annotation>... annotations) {
super(registry);
for (Class<? extends Annotation> annotation : annotations) {
addIncludeFilter(new AnnotationTypeFilter(annotation));
}
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)){
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
log.info("MyScanner scanner class name: {}", beanDefinition.getBeanClassName());
}
}
return beanDefinitionHolders;
}
}
测试
@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RemoteService {
/**
* 属性字段
* @return
*/
String value() default "";
}
@RemoteService
public class CarService {
public void run() {
System.out.println("car run...");
}
}
@RestController
public class ScannerController {
@Autowired
private CarService carService;
@GetMapping("/car")
public String index(){
carService.run();
return "success";
}
}
结果:
MyScanner scan packages: com.example.bootnacos
MyScanner scanner class name: com.example.bootnacos.scan.CarService
MyScanner scan annotation 【@RemoteService】 count: 【1】