Spring 中 ClassPathBeanDefinitionScanner 包扫描器的应用

代码演示

先定义两个实体类,不用 @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 的源码中这里会调用到,如下所示:

经验分享 程序员 微信小程序 职场和发展