ImportBeanDefinitionRegistrar——spring对外提供的注册bean功能

3,576 阅读2分钟

我们知道,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源码的时候再做分析。