借助ImportBeanDefinitionRegistrar接
2018-08-02 本文已影响0人
Top_Bear
ImportBeanDefinitionRegistrar
spring官方就是用这种方式,实现了@Component
、@Service
等注解的动态注入机制。定义一个ImportBeanDefinitionRegistrar的实现类,然后在有@Configuration
注解的配置类上使用@Import
导入
这里我们用一个简单的例子,我们需要实现类似@Componet
的功能,添加了@Mapper
注解的类会被自动加入到spring容器中。
首先创建一个@Mapper
注解,再新建一个CountryMapper
类,使用该Mapper注解。
@Documented
@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
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源码中的的定义
/**
* A bean definition scanner that detects bean candidates on the classpath,
* registering corresponding bean definitions with a given registry ({@code BeanFactory}
* or {@code ApplicationContext}).
*
需要继承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.faderw.school.domain");
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = {MapperAutoConfig.class})
public class DemoApplicationTests {
@Autowired
ApplicationContext applicationContext;
@Autowired
CountryMapper countryMapper;
@Test
public void contextLoads() {
System.out.println(countryMapper.getClass());
}
结果
class com.faderw.school.domain.CountryMapper