模拟spring整合mybatis

77 阅读1分钟

@(spring5.3,mybatis3.3) 从前两章节,了解要spring管理mybatis,主要是将mybatis需要的接口(也就是xxxMapper)放入spring容器,让spring来管理。 于是就有些许疑问:

-spring如何管理mybatis接口?

大致猜想:同样扫描获取接口数据,装配成BeanDefinition,注册成Bean对象 而spring中默认是不扫描接口,抽象类。但mybatis又需要接口。因此要想办法让spring扫描接口。

启动运行获取结果

image.png image.png

从源码来看,有两个地方会判断,是否需要放入BeanDefinition中。

image.png image.png

故而需要:添加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;
    }
}