代码演示
先定义两个实体类,不用 @Component 修饰,但是最终需要被 Spring 管理,代码如下:
public class Student {
}
public class Teacher {
}
然后定义注解 @BeansScanner 模拟 @ComponentScan 注解功能,代码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(BeansScannerRegistrar.class)
public @interface BeansScanner {
String basePackage() default "";
boolean on() default true;
}
这里通过 @Import 注解将 BeansScannerRegistrar 类导入进来,BeansScannerRegistrar 类如下所示:
public class BeansScannerRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// ClassPathBeanDefinitionScanner defaultScanner = new ClassPathBeanDefinitionScanner(registry);
BeanPackageScanner scanner = new BeanPackageScanner(registry);
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(BeansScanner.class.getName());
annotationAttributes.forEach((k,v)->{
System.out.println("获取到 BeansScanner 注解元数据= key= " + k+",val="+v);
});
String basePackage = (String)annotationAttributes.get("basePackage");
// 这里添加过滤条件,我们重写了过滤条件,默认扫描指定包下面全部 class 文件
scanner.addIncludeFilter(((metadataReader, metadataReaderFactory) -> true));
// defaultScanner.scan(basePackage);
scanner.doScan(basePackage);
}
}
最后编写测试类:
@BeansScanner(basePackage = "com.gwm.scan.beans")
public class TestBean {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class);
Student student = context.getBean(Student.class);
Teacher teacher = context.getBean(Teacher.class);
System.out.println("student = " + student);
System.out.println("teacher = " + teacher);
}
}
测试结果:
获取到 BeansScanner 注解元数据= key= basePackage,val=com.gwm.scan.beans
获取到 BeansScanner 注解元数据= key= on,val=true
student = com.gwm.scan.beans.Student@131ef10
teacher = com.gwm.scan.beans.Teacher@55b0dcab
可以发现这里还是借助了 ClassPathBeanDefinitionScanner 包扫描器,只是添加的过滤条件我们重写了,我们这里定义成这个包下面所有的 class 文件都可以封装成 BeanDefinition,并且注册到 BeanFactory 容器中。
我们从写的条件在 Spring 的源码中这里会调用到,如下所示: