ImportBeanDefinitionRegistrar接口
ImportBeanDefinitionRegistrar
spring官方就是用这种方式,实现@Component
、@Service
等注解的动态注入机制。定义一个ImportBeanDefinitionRegistrar的实现类,然后在有@Configuration
注解的配置类上使用@Import
导入
需要实现类似@Componet
的功能,添加了@Mapper
注解的类会被自动加入到spring容器中。
创建一个@Mapper
注解,再新建一个CountryMapper
类,使用该Mapper注解
@Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) public @interface Mapper { } @Mapper public class CountryMapper { }
创建MapperAutoConfiguredMyBatisRegistrar
实现ImportBeanDefinitionRegistrar
,同时可以继承一些Aware接口,获得spring的一些数据
BeanFactoryAware
ResourceLoaderAware
EnvironmentAware
使用@Import将MapperAutoConfiguredMyBatisRegistrar导入容器
public class MapperAutoConfiguredMyBatisRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanFactoryAware { private ResourceLoader resourceLoader; private BeanFactory beanFactory; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } }
实现registerBeanDefinitions
方法。但是有一个问题,我们并不知道需要register哪些bean。这里我们还需要借助一个类ClassPathBeanDefinitionScanner
,也就是扫描器,通过扫描器获取我们需要注册的bean。先简单看一下spring源码中的的定义
需要继承
ClassPathBeanDefinitionScanner
,扫描使用@Mapper
的注解的类,ClassPathBeanDefinitionScanner
又继承ClassPathScanningCandidateComponentProvider
类,ClassPathScanningCandidateComponentProvider
中有两个TypeFilter集合,includeFilters、excludeFilters。满足任意includeFilters会被加载,同样的满足任意excludeFilters不会被加载
@Slf4j public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{ public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { super(registry, useDefaultFilters); } protected void registerFilters() { addIncludeFilter(new AnnotationTypeFilter(Mapper.class)); } @Override protected Set<BeanDefinitionHolder> doScan(String... basePackages) { return super.doScan(basePackages); } }
registerFilters()方法,然后在我们的ImportBeanDefinitionRegistrar
实现类中调用
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false); scanner.setResourceLoader(resourceLoader); scanner.registerFilters(); scanner.doScan("com.smart.school.domain"); }
测试
@RunWith(SpringRunner.class) @SpringBootTest public class SrcDemoApplicationTests { @Resource private CountryMapper countryMapper; @Test public void contextLoads() { System.out.println(countryMapper.getClass()); } }
立志如山 静心求实