前言
本文继笔者学习mybatis源码后,仿照mybatis利用spring的拓展点将Mapper接口的代理类装入IOC的方法,实现自定义注解,让spring将指定包中有此注解的类装配进IOC容器来管理之,最终是放入容器的单例池中。
实现
1. 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface XxgComponent {
}
2. XxgComponentScannerConfigurer
2.1 实现BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor
,是spring给我们的一个拓展点,其自身继承自BeanFactoryPostProcessor
接口。
实现此接口的类,spring在初始化之后,会调用其以下两个方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
故我们可以在其实现类对应的方法中,执行我们的业务逻辑--即让spring扫描我们自定义注解对应的类。
2.2 代码
public class XxgComponentScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
private String basePackages;
public void setBasePackages(String basePackages) {
this.basePackages = basePackages;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
// left intentionally blank
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
XxgComponentScanner scanner = new XxgComponentScanner(registry);
scanner.registerFilters();
scanner.scan(basePackages);
}
}
3.扫描类XxgComponentScanner
3.1 ClassPathBeanDefinitionScanner
此类是spring用于扫描bean的类,
- 其
doScan()
方法会根据配置的拦截器规则,来将需要的类装配成BeanDefinitionHolder
对象并返回。 - 调用其
scan()
方法,其自身先调用doScan()
方法,然后会将扫描到的BeanDefinitionHolder
对象放入IOC容器
故,我们可以继承其类,然后:
- 不使用其默认拦截规则,而是根据我们自定义注解来拦截
- 重写其
doScan()
方法,首先调用父类的doScan()
获取到有我们自定义注解的BeanDefinitionHolder
对象们,然后可以遍历操作之,更改一些我们需要的参数,比如设置scope为单例等。
3.2 代码
public class XxgComponentScanner extends ClassPathBeanDefinitionScanner {
public XxgComponentScanner(BeanDefinitionRegistry registry) {
// 第二个参数:useDefaultFilters
// 设置为false,不使用默认拦截器
super(registry, false);
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 利用spring的扫描方法,扫描mapper接口所在的包,获取所有BeanDefinitionHolder
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
processBeanDefinitions(beanDefinitions);
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitionHolders) {
for (BeanDefinitionHolder holder : beanDefinitionHolders) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition)holder.getBeanDefinition();
beanDefinition.setScope("singleton");
System.out.println(beanDefinition.getBeanClassName());
}
}
// 定义拦截器,让spring装配我们需要的对象到IOC容器
public void registerFilters() {
// 设置 只扫描有@XxgComponent注解的类
addIncludeFilter(new AnnotationTypeFilter(XxgComponent.class));
// 设置 忽略 package-info.java addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
}
4.让spring管理我们的XxgComponentScannerConfigurer
<!-- 测试自定义装配bean注解-->
<bean class="com.dbc.springMybatis.util.XxgComponentScannerConfigurer">
<property name="basePackages" value="com.dbc.springMybatis.myBean"/>
</bean>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。