若要使用ClassPathBeanDefinitionScanner对象,必须一个BeanDefinitionRegistry作为入参传入
获取该对象的3种方法
1,通过一些BeanFactory的实现类,但是并不是所有BeanFactory都支持,默认ApplicationContext就不支持,强转又有风险。
2,通过Condition接口的方法,但是这样做太拖离Condition业务的本意。要在其上实现无关的扫描功能。
3,使用ImportBeanDefinitionRegistrar,也就是MyBatis与Spring整合的方式。(我原来最不想用这种方式,我想实现,在spring配置文件中指定扫描路径就开启,没有指定就不扫描,而这种方式必须要加个Import注解,最终使用注解实现)
具体使用的一些坑
ImportBeanDefinitionRegistrar
//该组件必须加在@Import中使用 直接注入容器registerBeanDefinitions方法不会被调用
public class ApiMapperScannerRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(ApiMapperScan.class.getName()));//获取@Import所标注的注解信息
ApiMapperScanner scanner = new ApiMapperScanner(registry);
// AnnotationAttributes有获取各种注解信息的方法
scanner.doScan(annoAttrs.getStringArray("value"));
}
}
注意若扫描空数组会报错
ClassPathBeanDefinitionScanner使用
public class ApiMapperScanner extends ClassPathBeanDefinitionScanner{
public ApiMapperScanner(BeanDefinitionRegistry registry) {
super(registry,false);//默认只扫描@Component与@ManagedBean建议取消默认的
//重新添加过滤规则 类似注解组件扫描
addIncludeFilter(new AnnotationTypeFilter(ApiMapper.class));
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> definitionHolders = super.doScan(basePackages);
handleBeanDefinitionHolder(definitionHolders);//对扫描结果进行拦截处理
return definitionHolders;
}
private void handleBeanDefinitionHolder(Set<BeanDefinitionHolder> definitionHolders) {
for (BeanDefinitionHolder holder:definitionHolders){
BeanDefinition definition = holder.getBeanDefinition();
//保留原来的接口
String className = definition.getBeanClassName();
//替换Bean的实现类
definition.setBeanClassName("com.sk.api.mapper.factory.ApiMapperFactoryBean");
MutablePropertyValues values = definition.getPropertyValues();
//通过Bean的名字添加引用属性
values.add("apiMapper",new RuntimeBeanReference("apiMapper"));
//若类型不匹配Spring的类型转换器会生效
values.add("targetClass",className);
logger.info("ApiMapper Is Mapper:"+className);
}
}
@Override//对扫描对象的条件限制
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface()&&beanDefinition.getMetadata().isIndependent();
}
}
注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
// 一定要使用@Import导入
@Import(ApiMapperScannerRegistrar.class)
public @interface ApiMapperScan {
String[] value();
}
使用效果
指定扫描路径
对路径下的接口自动代理
主要是对ApiMapper的封装使它支持类似MyBatis的包扫描功能
ApiMapper地址:https://blog.csdn.net/weixin_44598449/article/details/118658663
本项目完整地址:https://gitee.com/shaokang123/api-mapper-spring-boot-starter