我们知道,spring在启动的时候会把我们定义好的类转化成BeanDefinition注册到容器中(其实就是put到eanDefinitionMap中)。其实,除了spring帮我自动完成注册之外,还给我们提供了自己手动注册的功能。这就要依靠大名鼎鼎的ImportBeanDefinitionRegistrar来实现这样的功能了。
另:关于ImportSelector可以看这篇文章了解 Spring源码阅读之ImportSelector使用案例
使用demon
使用起来也很简单,我们自己定义个类直接实现ImportBeanDefinitionRegistrar接口即可。这里我就直接附上我写的一个简单案例了。
MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
scanner.registerFilters();
scanner.doScan("com.study.service");
}
}
上面的代码中,我们通过引入自己的扫描器MyClassPathBeanDefinitionScanner扫描出com.study.service下面的符合条件的类,并转换成BeanDefinition注册到spring容器中。
MyClassPathBeanDefinitionScanner
public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
super(registry, useDefaultFilters);
}
protected void registerFilters() {
addIncludeFilter(new AnnotationTypeFilter(MyMapper.class));
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
return super.doScan(basePackages);
}
}
在自己定义的扫描器中,主要是定义了扫描的规则。将满足规则的扫描出来转换成BeanDefinition,这里定义的规则是添加了MyMapper注解的类。
MyService
现在,定义一个类,添加MyMapper注解,手动注册进spring容器中。
@MyMapper
public class MyService {
}
MyMapper
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMapper {
}
AppConfig
编写一个配置类,引入自己的ImportBeanDefinitionRegistrar
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfig {
}
Test
编写测试类测试是否能成功注册
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
MyService myService = (MyService)context.getBean("myService");
System.out.println(myService);
}
}
执行测试类,控制台输出如下
com.study.service.MyService@25618e91
说明手动注册BeanDefinition成功。
官方使用案例
在mybatis官方为spring实现的版本就是通过实现ImportBeanDefinitionRegistrar接口,扫描出Mapper变成BeanDefinition注册到spring容器中。但是这个BeanDefinition的beanClass最终并不是具体的Mapper类型,而是MapperFactoryBean。也就是说,一个Mapper在spring容器中都会对应一个MapperFactoryBean。具体的过程在分析mybatis源码的时候再做分析。