@(spring5.3,mybatis3.3) 从前两章节,了解要spring管理mybatis,主要是将mybatis需要的接口(也就是xxxMapper)放入spring容器,让spring来管理。 于是就有些许疑问:
-spring如何管理mybatis接口?
大致猜想:同样扫描获取接口数据,装配成BeanDefinition,注册成Bean对象 而spring中默认是不扫描接口,抽象类。但mybatis又需要接口。因此要想办法让spring扫描接口。
启动运行获取结果
从源码来看,有两个地方会判断,是否需要放入BeanDefinition中。
故而需要:添加includeFilters
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
// 扫描路径
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName());
String path = (String) annotationAttributes.get("path");
MapperBeanDefinitionScanner scanner = new MapperBeanDefinitionScanner(registry);
//表示添加过滤器针对接口,以便扫描mybatis接口
scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> metadataReader.getAnnotationMetadata().isInterface());
scanner.scan(path);
}
扫描类型:只针对xx.xx下的接口继承并重写 ClassPathBeanDefinitionScanner#isCandidateComponent
/**
* 只针对接口扫描
*
* @param beanDefinition
* @return
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface();
}
同时需要处理扫描逻辑,组装BeanDefinition,来生成FactoryBean
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
//将每个接口定义成BeanDefinition
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
//将接口放入MapperFactoryBean构造方法
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
//设置factoryBean
beanDefinition.setBeanClassName(MapperFactoryBean.class.getName());
//自动查找所有set方法并调用
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
return beanDefinitionHolders;
}
接下来需要处理FactoryBean
public class MapperFactoryBean implements FactoryBean {
//表示传入的mybatis接口
private Class mapperInterface;
private SqlSession sqlSession;
//此处可以用Autowired 或
// beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
sqlSessionFactory.getConfiguration().addMapper(mapperInterface);
this.sqlSession = sqlSessionFactory.openSession();
}
public MapperFactoryBean(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public Object getObject() throws Exception {
//得到mapper代理对象
return sqlSession.getMapper(mapperInterface);
}
//当前类的类型
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
}