共计 2818 个字符,预计需要花费 8 分钟才能阅读完成。
前言
本文继笔者学习 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>
正文完