前言
spring@ComponentScan("") 注解默认是不扫描interface的,一般在开发的时候我们不需要在interface上面添加 @Component 注解,添加上也是无效的。但我们在使用mybatis在进行项目开发的时候经常会使用mapper interface接口来注入到service层中,这是因为mybatis 会将我们需要的mapper 接口的interface 生成一个代理对象注入到service层中。其实我们重写spring 中的ClassPathBeanDefinitionScanner 来实现对interface 扫描到spring 容器中。
准备工作
在com.boshrong.spring.mapper 中我们定义了两个接口。 我们要实现将这两个接口注入到Spring 容器中。
编写扫描类
package com.boshrong.mybatis;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import java.io.IOException;
import java.util.Set;
public class RongScanner extends ClassPathBeanDefinitionScanner {
public RongScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
//判断是否为合格的compoent
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
return metadataReader.getClassMetadata().isInterface();
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface();
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
//返回的是beandefinition
return beanDefinitionHolders;
}
}
这个扫描类继承了ClassPathBeanDefinitionScanner,并重写了两个iisCandidateComponent 方法注意两个的参数是不一致的,让其支持对interface 扫描。然后重写了doScan方法,doScan方法 返回的是beandefinition.在spring 底层所有声明式bean的定义都是通过beandefinition来实现的。其基本结构就是下面形式
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//设置bean的类型
beanDefinition.setBeanClass(Aservice.class);
// 往spring 容器中注册
applicationContext.registerBeanDefinition("aservice",beanDefinition);
二 创建Register 相关类进行创建
package com.boshrong.mybatis;
import com.boshrong.spring.mapper.OrderMapper;
import com.boshrong.spring.mapper.UserMapper;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
public class RongImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
// 扫描--->
// 传入注册表
String path="com.boshrong.spring.mapper";
//扫描注册表
RongScanner rongScanner=new RongScanner(registry);
// return true 表示不用加compoent注解也能被扫描
rongScanner.addIncludeFilter(new TypeFilter() {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
rongScanner.doScan(path); //BeanDefinition --> register
}
}
我们实现ImportBeanDefinitionRegistrar 接口和registerBeanDefinitions 方法。这样的好处在于我们可以通过@Import(RongImportBeanDefinitionRegister.class) 导入相关类,因为有Spring提供的接口。spring 自动调用其中的方法。
运行结果
我们可以在doScan上面打上断点,查看beanDefinitionHolders的值。断点结果如下。